联系Django Admin的模型历史

时间:2009-06-12 16:32:47

标签: django django-models django-admin

设置:

  • 我正在开发一个Django应用程序,它允许用户在数据库中创建一个对象,然后根据需要返回并编辑它。
  • Django的管理站点保存了通过管理站点对对象所做更改的历史记录。

问题:

  • 如何将我的应用程序挂钩到管理网站的更改历史记录中,以便查看用户对其“内容”所做更改的历史记录?

6 个答案:

答案 0 :(得分:123)

管理员历史记录只是一个应用程序,就像任何其他Django应用程序一样,但管理站点上的特殊位置除外。

该模型位于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是当然改变的对象。

现在我看到丹尼尔的回答并同意他的观点,这是非常有限的。

在我看来,更强的方法是在他的书Pro Django中使用Marty Alchin的代码(参见保持历史记录从第263页开始)。有一个应用程序django-simple-history,它实现并扩展了这种方法(docs here)。

答案 1 :(得分:21)

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

他们并不是特别聪明,并且与管理员紧密相关,因此您最好只使用这些创意并为您的应用创建自己的版本。

答案 2 :(得分:10)

我知道这个问题已经过时了,但截至今天(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>

答案 3 :(得分:7)

要添加已经说过的内容,以下是其他一些资源:

(1)我一直在使用名为django-reversion的应用程序,该应用程序“挂钩”管理员历史记录并实际添加到其中。如果你想要一些可以看的好样例代码。

(2)如果您决定推出自己的历史记录功能,则django会提供您可以订阅以让您的应用处理的信号,例如,每个历史对象的post_save。每次保存历史记录日志条目时,您的代码都会运行。 Doc:Django signals

答案 4 :(得分:2)

示例代码

您好,

我最近攻击了一些日志记录到我们的服务器库存数据库的“更新”视图。我想我会分享我的“示例”代码。下面的函数使用我们的一个“服务器”对象,一个已更改的事物列表,以及一个ADDITION或CHANGE的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."

答案 5 :(得分:1)

示例代码:

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()类。