联系Django Admin的模型历史

akd*_*dom 85 django django-models django-admin

设置:

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

问题:

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

Van*_*ale 127

管理历史记录只是一个类似于任何其他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
)
Run Code Online (Sandbox Code Playgroud)

object当然,改变的对象在哪里.

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

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

  • 自从回答这个问题以来,Marty Alchin的方法已经在一个名为[django-simple-history](https://bitbucket.org/q/django-simple-history/)的应用程序中开源和扩展. (17认同)
  • `来自django.utils.encoding import force_unicode`为'force_unicode' (8认同)
  • 不要忘记:从django.contrib.contenttypes.models导入ContentType.另外,force_unicode也是它们自己的功能. (7认同)
  • **django-simple-history**的新家似乎是:https://github.com/treyhunner/django-simple-history关于RTD的更多信息https://django-simple-history.readthedocs.org/ EN /最新/ (4认同)
  • 一个好的方法也可以检查[djangopackages.com上的[比较网格](https://www.djangopackages.com/grids/g/versioning/),其中django-simple-history和其他解决方案(如CleanerVersion或django-reversion) )进行比较. (3认同)
  • 关于**保存历史记录**的部分仅出现在**Pro Django**一书中的第一版中。 (2认同)

Dan*_*man 21

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

虽然他们并不是特别聪明,并且与管理员紧密相关,所以你可能最好只使用这些创意并为你的应用创建自己的版本.

  • 这仍然是真的吗? (4认同)

dav*_*4jr 11

我知道这个问题已经过时了,但截至今天(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})
Run Code Online (Sandbox Code Playgroud)

如上面的代码片段所示,我正在从LogEntry模型创建一个基本的查询集(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>
Run Code Online (Sandbox Code Playgroud)


T. *_*one 7

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

(1)我一直在使用一个名为django-reversion的应用程序,该应用程序"挂钩"管理历史记录并实际添加到它.如果你想要一些样本代码,那将是一个好看的地方.

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

  • 我强烈**建议反对django-reversion.从概念上讲,这是一个好主意,但实施起来很糟糕.我在生产现场使用它,这是一场噩梦.它起初效果很好,但我最终发现该应用程序根本不具备可扩展性,因此对于任何具有半频率更改的模型,您的管理员将在几个月内变得无法使用,因为它使用的查询非常低效. (2认同)