Привязка к истории моделей Django Admin


Настройки:

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

Вопрос:

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

5 ответов:

история администратора-это просто приложение, как и любое другое приложение Django, за исключением специального размещения на сайте администратора.

модель в Django.ВНО.администратор.модели.Экземпляр 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 объект, который был изменен конечно.

теперь я вижу ответ Даниила и согласен с ним, это довольно ограниченный.

на мой взгляд, более сильный подход заключается в использовании кода от Марти Алчина в его книге Про Джанго (см. Ведение Исторических Записей начиная со страницы 263). Есть приложение django-простая история, который реализует и расширяет этот подход (документы здесь).

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

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

Я знаю, что этот вопрос старый, но на сегодняшний день (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>

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

(1) я работаю с приложением под названием Джанго-реверсия который "подключается" к истории администратора и фактически добавляет к ней. Если вам нужен пример кода, который будет хорошим местом для поиска.

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

Пример Кода

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

недавно я взломал некоторые журналы для просмотра "обновления" для нашей базы данных инвентаризации серверов. Я решил, что поделюсь своим" примером " кода. Следующая функция принимает один из наших" серверных " объектов, список вещей, которые были изменены, и action_flag либо добавления, либо изменения. Это упрощает вещи немного, где добавление означает " добавлен новый сервер."Более гибкий подход позволит добавить атрибут к сервер. Конечно, было достаточно сложно провести аудит наших существующих функций, чтобы определить, действительно ли произошли изменения, поэтому я с удовольствием регистрирую новые атрибуты как "изменение".

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