Historia administratora to po prostu aplikacja, jak każda inna aplikacja Django, z wyjątkiem specjalnego miejsca na stronie administratora.
Model znajduje się w django.contrib.admin.models.LogEntry.
Kiedy użytkownik dokona zmiany, dodaj do dziennika w ten sposób (skradziony bezwstydnie z 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
)
gdzie object
jest przedmiot, który został oczywiście zmieniony.
Teraz widzę odpowiedź Daniela i zgadzam się z nim, jest dość ograniczona.
Moim zdaniem silniejszym podejściem jest użycie kodu Marty'ego Alchina w jego książce Pro Django (patrz Prowadzenie zapisów historycznych od strony 263). Istnieje aplikacja django-simple-history, która implementuje i rozszerza to podejście ( dokumentacja tutaj ).
from django.utils.encoding import force_unicode
dla „force_unicode”Dziennik historii zmian administratora jest zdefiniowany w programie
django.contrib.admin.models
, aw klasiehistory_view
standardowej znajduje się metodaModelAdmin
.Nie są jednak szczególnie sprytne i dość ściśle powiązane z administratorem, więc najlepiej będzie, jeśli użyjesz ich do pomysłów i stworzenia własnej wersji aplikacji.
źródło
Wiem, że to pytanie jest stare, ale na dzień dzisiejszy (Django 1.9) elementy historii Django są bardziej solidne niż były w dniu tego pytania. W bieżącym projekcie musiałem pobrać ostatnie elementy historii i umieścić je na liście rozwijanej na pasku nawigacyjnym. Tak to zrobiłem i było bardzo proste:
*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})
Jak widać na powyższym fragmencie kodu, tworzę podstawowy zestaw zapytań z modelu LogEntry (django.contrib.admin.models.py jest tam, gdzie znajduje się w django 1.9) i wykluczam elementy, w których nie są wprowadzane żadne zmiany, zamawiając go przez czas działania i pokazanie tylko ostatnich 20 dzienników. Otrzymuję też kolejny przedmiot z samą liczbą. Jeśli spojrzysz na model LogEntry, zobaczysz nazwy pól, których Django użył do wycofania potrzebnych fragmentów danych. W moim konkretnym przypadku oto, czego użyłem w moim szablonie:
Link do zdjęcia produktu końcowego
*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>
źródło
Aby dodać do tego, co już zostało powiedziane, oto kilka innych zasobów dla Ciebie:
(1) Pracowałem z aplikacją o nazwie django-reversion, która „zaczepia się” o historię administratora i dodaje do niej. Jeśli potrzebujesz przykładowego kodu, byłoby to dobre miejsce do obejrzenia.
(2) Jeśli zdecydowałeś się rzucić własną funkcję historii, django dostarcza sygnały, które możesz zasubskrybować, aby twoja aplikacja obsługiwała, na przykład, post_save dla każdego obiektu historii. Twój kod byłby uruchamiany za każdym razem, gdy zapisywana byłaby pozycja dziennika historii. Doc: Sygnały Django
źródło
Przykładowy kod
Witaj,
Niedawno włamałem się do niektórych funkcji logowania do widoku „aktualizacji” naszej bazy danych spisu serwerów. Pomyślałem, że udostępnię mój „przykładowy” kod. Następująca funkcja pobiera jeden z naszych obiektów „Serwer”, listę rzeczy, które zostały zmienione, oraz flagę akcji ADDITION lub CHANGE. Trochę upraszcza to, gdzie DODATEK oznacza „dodano nowy serwer”. Bardziej elastyczne podejście pozwoliłoby na dodanie atrybutu do serwera. Oczywiście wystarczająco trudne było przeprowadzenie audytu naszych istniejących funkcji w celu ustalenia, czy rzeczywiście zaszła zmiana, więc z przyjemnością rejestruję nowe atrybuty jako „zmianę”.
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."
źródło