Привязка к истории моделей Django Admin - PullRequest
84 голосов
/ 12 июня 2009

Настройка:

  • Я работаю над приложением Django, которое позволяет пользователям создавать объекты в базе данных, а затем возвращаться и редактировать их столько, сколько они хотят.
  • Сайт администратора Django хранит историю изменений, внесенных в объекты через сайт администратора.

Вопрос:

  • Как подключить мое приложение к истории изменений сайта администратора, чтобы я мог видеть историю изменений, которые пользователи вносят в свое "содержимое"?

Ответы [ 5 ]

124 голосов
/ 12 июня 2009

История администратора - это приложение, подобное любому другому приложению 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 (см. Ведение исторических записей начиная со страницы 263). Существует приложение django-simple-history , которое реализует и расширяет этот подход ( документы здесь ).

21 голосов
/ 12 июня 2009

Журнал истории изменений администратора определен в django.contrib.admin.models, а в стандартном ModelAdmin классе есть метод history_view.

Хотя они не очень умны и довольно тесно связаны с администратором, поэтому вам лучше всего использовать их для идей и создать собственную версию для своего приложения.

10 голосов
/ 07 марта 2016

Я знаю, что этот вопрос старый, но на сегодняшний день (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 использовал для получения необходимых вам данных. Для моего конкретного случая вот что я использовал в своем шаблоне:

Ссылка на изображение конечного продукта

*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>
7 голосов
/ 31 июля 2009

Чтобы добавить к тому, что уже было сказано, вот некоторые другие ресурсы для вас:

(1) Я работал с приложением под названием django-reversion , которое «цепляет» историю администратора и фактически добавляет к ней. Если вам нужен пример кода, это было бы хорошим местом для поиска.

(2) Если вы решили развернуть свою собственную функцию истории, django предоставляет сигналы, на которые вы можете подписаться, чтобы иметь свое приложение, например post_save для каждого объекта истории. Ваш код будет запускаться каждый раз при сохранении записи журнала. Док: Джанго сигналы

2 голосов
/ 07 июля 2010

Пример кода

Здравствуйте,

Недавно я взломал журнал для обновления представления нашей базы данных инвентаризации сервера. Я подумал, что поделюсь своим «примером» кода. Следующая функция берет один из наших объектов «Сервер», список вещей, которые были изменены, и флаг action_flag ADDITION или CHANGE. Это немного упрощает ситуацию, когда 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] + "."
        # /725249/privyazka-k-istorii-modelei-django-admin
        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."
...