La configuration:
La question:
L'historique d'administration est juste une application comme toute autre application Django, à l'exception du placement spécial sur le site d'administration.
Le modèle se trouve dans Django.contrib.admin.models.LogEntry.
Lorsqu'un utilisateur effectue un changement, ajoutez-le au journal comme ceci (volé sans vergogne à contrib/admin/options.py:
from Django.contrib.admin.models import LogEntry, ADDITION
LogEntry.objects.log_action(
user_id = request.user.pk,
content_type_id = ContentType.objects.get_for_model(object).pk,
object_id = object.pk,
object_repr = force_unicode(object),
action_flag = ADDITION
)
où object
est bien sûr l'objet qui a été modifié.
Maintenant je vois la réponse de Daniel et je suis d'accord avec lui, c'est assez limité.
À mon avis, une approche plus forte consiste à utiliser le code de Marty Alchin dans son livre Pro Django (voir Tenir des registres historiques à partir de à la page 263). Il existe une application Django-simple-history qui implémente et étend cette approche ( docs here ).
Le journal de l'historique des modifications de l'administrateur est défini dans Django.contrib.admin.models
, et il y a un history_view
méthode dans la classe standard ModelAdmin
.
Cependant, ils ne sont pas particulièrement intelligents et assez étroitement liés à l'administrateur, il est donc préférable de simplement les utiliser pour des idées et de créer votre propre version pour votre application.
Je sais que cette question est ancienne, mais à ce jour (Django 1.9), les éléments de l'histoire de Django sont plus robustes qu'ils ne l'étaient à la date de cette question. Dans un projet en cours, j'avais besoin d'obtenir les éléments d'historique récents et de les mettre dans une liste déroulante à partir de la barre de navigation. Voici comment je l'ai fait et j'ai été très simple:
*views.py*
from Django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
def main(request, template):
logs = LogEntry.objects.exclude(change_message="No fields changed.").order_by('-action_time')[:20]
logCount = LogEntry.objects.exclude(change_message="No fields changed.").order_by('-action_time')[:20].count()
return render(request, template, {"logs":logs, "logCount":logCount})
Comme vu dans l'extrait de code ci-dessus, je crée un ensemble de requêtes de base à partir du modèle LogEntry (Django.contrib.admin.models.py est l'endroit où il se trouve dans Django 1.9) et en excluant les éléments où aucun changement n'est impliqué, en le classant par temps d'action et en affichant uniquement les 20 derniers journaux. J'obtiens également un autre élément avec juste le nombre. Si vous regardez le modèle LogEntry, vous pouvez voir les noms de champ qui Django a utilisé afin de retirer les données dont vous avez besoin. Pour mon cas spécifique, voici ce que j'ai utilisé dans mon modèle:
Lien vers l'image du produit final
*template.html*
<ul class="dropdown-menu">
<li class="external">
<h3><span class="bold">{{ logCount }}</span> Notification(s) </h3>
<a href="{% url 'index' %}"> View All </a>
</li>
{% if logs %}
<ul class="dropdown-menu-list scroller actionlist" data-handle-color="#637283" style="height: 250px;">
{% for log in logs %}
<li>
<a href="javascript:;">
<span class="time">{{ log.action_time|date:"m/d/Y - g:ia" }} </span>
<span class="details">
{% if log.action_flag == 1 %}
<span class="label label-sm label-icon label-success">
<i class="fa fa-plus"></i>
</span>
{% Elif log.action_flag == 2 %}
<span class="label label-sm label-icon label-info">
<i class="fa fa-edit"></i>
</span>
{% Elif log.action_flag == 3 %}
<span class="label label-sm label-icon label-danger">
<i class="fa fa-minus"></i>
</span>
{% endif %}
{{ log.content_type|capfirst }}: {{ log }}
</span>
</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>{% trans "This object doesn't have a change history. It probably wasn't added via this admin site." %}</p>
{% endif %}
</li>
</ul>
Pour ajouter à ce qui a déjà été dit, voici d'autres ressources pour vous:
(1) J'ai travaillé avec une application appelée Django-reversion qui "se connecte" à l'historique d'administration et y ajoute en fait. Si vous vouliez un exemple de code, ce serait un bon endroit pour regarder.
(2) Si vous décidez de lancer votre propre fonctionnalité d'historique Django fournit des signaux auxquels vous pouvez vous abonner pour que votre application gère, par exemple, post_save pour chaque objet d'historique. Votre code s'exécutera à chaque fois une entrée du journal d'historique a été enregistrée. Doc: signaux Django
Bonjour,
J'ai récemment piraté une connexion à une vue "mise à jour" de notre base de données d'inventaire de serveur. J'ai pensé que je partagerais mon "exemple" de code. La fonction qui suit prend l'un de nos objets "Serveur", une liste des choses qui ont été modifiées et un indicateur action_DITIF ou CHANGE. Cela simplifie un peu les choses où ADDITION signifie "ajouté un nouveau serveur". Une approche plus flexible permettrait d'ajouter un attribut à un serveur. Bien sûr, il était suffisamment difficile de vérifier nos fonctions existantes pour déterminer si des changements avaient effectivement eu lieu, donc je suis assez heureux d'enregistrer de nouveaux attributs en tant que "changement".
from Django.contrib.admin.models import LogEntry, User, ADDITION, CHANGE
from Django.contrib.contenttypes.models import ContentType
def update_server_admin_log(server, updated_list, action_flag):
"""Log changes to Admin log."""
if updated_list or action_flag == ADDITION:
if action_flag == ADDITION:
change_message = "Added server %s with hostname %s." % (server.serial, server.name)
# http://dannyman.toldme.com/2010/06/30/python-list-comma-comma-and/
Elif len(updated_list) > 1:
change_message = "Changed " + ", ".join(map(str, updated_list[:-1])) + " and " + updated_list[-1] + "."
else:
change_message = "Changed " + updated_list[0] + "."
# http://stackoverflow.com/questions/987669/tying-in-to-Django-admins-model-history
try:
LogEntry.objects.log_action(
# The "update" user added just for this purpose -- you probably want request.user.id
user_id = User.objects.get(username='update').id,
content_type_id = ContentType.objects.get_for_model(server).id,
object_id = server.id,
# HW serial number of our local "Server" object -- definitely change when adapting ;)
object_repr = server.serial,
change_message = change_message,
action_flag = action_flag,
)
except:
print "Failed to log action."