设置:
我正在开发一个 Django 应用程序,它允许用户在数据库中创建一个对象,然后返回并根据需要进行编辑。
Django 的管理站点保留了通过管理站点对对象所做更改的历史记录。
问题:
如何将我的应用程序连接到管理站点的更改历史记录,以便我可以查看用户对其“内容”所做更改的历史记录?
管理历史记录只是一个应用程序,就像任何其他 Django 应用程序一样,除了在管理站点上的特殊位置。
模型在 django.contrib.admin.models.LogEntry 中。
当用户进行更改时,像这样添加到日志中(从 contrib/admin/options.py 中无耻地窃取:
from django.utils.encoding import force_unicode
from django.contrib.contenttypes.models import ContentType
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 页开始的保留历史记录)。有一个应用程序 django-simple-history 实现并扩展了这种方法 (docs here)。
管理员的更改历史记录在 django.contrib.admin.models
中定义,标准 ModelAdmin
类中有一个 history_view
方法。
不过,它们并不是特别聪明,并且与管理员的耦合相当紧密,因此您最好将它们用于创意并为您的应用创建自己的版本。
我知道这个问题已经过时了,但截至今天(Django 1.9),Django 的历史记录项比提出这个问题的日期更强大。在当前项目中,我需要获取最近的历史记录项并将它们放入导航栏的下拉列表中。我就是这样做的,而且非常直截了当:
*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 模型(django.contrib.admin.models.py 是它在 django 1.9 中的位置)创建一个基本查询集,并排除不涉及更改的项目,按以下顺序排序动作时间,仅显示过去 20 条日志。我还得到了另一个只有计数的项目。如果您查看 LogEntry 模型,您可以看到 Django 使用的字段名称以拉回您需要的数据片段。对于我的具体情况,这是我在模板中使用的内容:
Link to Image Of Final Product
*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>
为了补充已经说过的内容,这里有一些其他资源可供您使用:
(1) 我一直在使用一个名为 django-reversion 的应用程序,它“挂钩”管理历史记录并实际添加到其中。如果您想要一些示例代码,那将是一个很好的地方。
(2) 如果您决定推出自己的历史记录功能,django 会提供您可以订阅的信号以让您的应用程序处理,例如,每个历史记录对象的 post_save。每次保存历史日志条目时,您的代码都会运行。文档:Django signals
示例代码
你好,
我最近在我们的服务器库存数据库的“更新”视图中进行了一些日志记录。我想我会分享我的“示例”代码。下面的函数采用我们的“服务器”对象之一、已更改的内容列表以及添加或更改的 action_flag。它简化了一些事情,其中 ADDITION 意味着“添加了一个新服务器”。一种更灵活的方法将允许向服务器添加属性。当然,审核我们现有的功能以确定是否确实发生了更改是非常具有挑战性的,因此我很高兴将新属性记录为“更改”。
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."
示例代码:
from django.contrib.contenttypes.models import ContentType
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=str(object),
action_flag=ADDITION,
)
对象是您要在管理站点日志中注册的对象。您可以尝试使用参数 object_repr 中的 str() 类。
不定期副业成功案例分享
from django.utils.encoding import force_unicode
用于“force_unicode”