绑定到Django Admin的模型历史

设置:

  • 我正在研究一个Django应用程序,它允许用户在数据库中创build一个对象,然后返回并按照自己的意愿对其进行编辑。
  • Django的pipe理站点保留了通过pipe理站点对对象所做更改的历史logging。

问题:

  • 如何将我的应用程序挂接到pipe理站点的更改历史logging,以便我可以查看用户对其“内容”所做更改的历史logging?

pipe理历史只是一个像任何其他Django应用程序的应用程序,除了在pipe理网站上的特殊位置。

该模型在django.contrib.admin.models.LogEntry中。

当用户进行更改时,请像这样添加到日志中(从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 ) 

object是当然被改变的对象。

现在我看到但以理的回答,并同意他,这是相当有限的。

在我看来,一个更强有力的方法是使用Marty Alchin在他的书“ Pro Django”中的代码(参见第263页的“ 保存历史logging” )。 有一个应用程序django-simple-history实现并扩展了这个方法( 文档在这里 )。

pipe理员的更改历史日志在django.contrib.admin.models定义,标准ModelAdmin类中有一个history_view方法。

虽然他们并不是特别聪明,而且与pipe理员紧密相连,所以你可能最好使用这些想法,为你的应用程序创build自己的版本。

为了增加已经说过的话,这里有一些其他的资源给你:

(1)我一直在使用一个名为django-reversion的应用程序,该应用程序“挂钩”pipe理历史logging,并实际添加到该应用程序中。 如果你想要一些示例代码,这将是一个很好的地方看。

(2)如果你决定推出你自己的历史function,django提供了你可以订阅的信号来让你的应用程序处理,比如每个历史对象的post_save。 每次保存历史logging条目时,您的代码都会运行。 Doc: Django信号

我知道这个问题已经很老了,但截至今天(Django 1.9),Django的历史条目比这个问题的date更为强大。 在当前的项目中,我需要获取最近的历史logging,并将其放置在导航栏的下拉菜单中。 我是这么做的,而且非常简单:

 *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}) 

从上面的代码片断可以看出,我从LogEntry模型创build了一个基本的查询集(django.contrib.admin.models.py就是它在django 1.9中的位置),排除了没有涉及到更改的项目,行动的时间,只显示过去20日志。 我也正在计数另一个项目。 如果查看LogEntry模型,可以看到Django使用的字段名称,以便撤回所需的数据。 对于我的具体情况,这是我在我的模板中使用的:

链接到最终产品的图像

 *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> 

示例代码

你好,

我最近在某些日志logging中对我们的服务器库存数据库进行了“更新”视图。 我想我会分享我的“示例”代码。 下面的函数接受我们的“服务器”对象之一,已经被更改的事物列表以及添加或更改的action_flag。 它简化了ADDITION的意思是“添加一个新的服务器”的一点点。 更灵活的方法将允许向服务器添加属性。 当然,审计我们现有的function以确定是否真的发生了变化是非常具有挑战性的,所以我很高兴能够logging新的属性作为“变化”。

 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."