Django Admin의 모델 히스토리에 연결


94

설정:

  • 사용자가 데이터베이스에 개체를 만든 다음 원하는만큼 돌아가서 편집 할 수있는 Django 애플리케이션을 개발 중입니다.
  • Django의 관리 사이트는 관리 사이트를 통해 개체에 적용된 변경 내역을 유지합니다.

질문:

  • 사용자가 "콘텐츠"에 대한 변경 내역을 볼 수 있도록 내 응용 프로그램을 관리 사이트의 변경 내역에 연결하려면 어떻게해야합니까?

답변:


136

관리자 기록은 다른 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 페이지에서 시작 하는 Historical Records 유지 참조 ). 이 접근 방식을 구현하고 확장 하는 애플리케이션 django-simple-history 가 있습니다 ( docs here ).


7
잊지 마세요 : django.contrib.contenttypes.models import ContentType. 또한 force_unicode는 자체 기능입니다.
sakabako

10
from django.utils.encoding import force_unicode'force_unicode'에 대한
mmrs151

17
이 질문에 대한 답변 이후 Marty Alchin의 접근 방식은 오픈 소스이며 django-simple-history 라는 애플리케이션에서 확장되었습니다 .
Trey Hunner 2011 년

5
의 새 집 장고 - 간단한 역사 : 것 같다 github.com/treyhunner/django-simple-history RTD에 대한 자세한 정보 django-simple-history.readthedocs.org/en/latest
브루투스

3
django-simple-history 및 기타 솔루션 (CleanerVersion 또는 django-reversion과 같은)이 비교 되는 djangopackages.com 에서 비교 그리드 를 확인하는 것도 좋은 방법 입니다.
maennel

22

관리자의 변경 내역 로그는에 정의 되어 있으며 표준 클래스 django.contrib.admin.models에는 history_view메서드가 ModelAdmin있습니다.

하지만 특별히 영리하지 않고 관리자와 밀접하게 연결되어 있으므로 아이디어를 위해 이것을 사용하고 앱을위한 고유 한 버전을 만드는 것이 가장 좋습니다.


4
여전히 사실입니까?
여기를 클릭하십시오.

12

이 질문이 오래되었다는 것을 알고 있지만 오늘 (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

이미 언급 한 내용을 추가하려면 다음과 같은 다른 리소스를 참조하세요.

(1) 저는 관리자 기록에 '연결'되어 실제로 추가되는 django-reversion 이라는 앱으로 작업 해 왔습니다 . 보기 좋은 곳이 될 샘플 코드를 원한다면.

(2) 자신의 히스토리 기능을 롤링하기로 결정한 경우 django는 각 히스토리 객체에 대한 post_save와 같이 앱을 처리하도록 구독 할 수있는 신호를 제공합니다. 기록 로그 항목이 저장 될 때마다 코드가 실행됩니다. Doc : Django 신호


3
나는 것이다 강하게 장고 - 복귀에 대해 권장합니다. 개념적으로는 좋은 생각이지만 구현은 끔찍합니다. 나는 이것을 생산 현장에서 사용했고 그것은 악몽이었습니다. 처음에는 훌륭하게 작동했지만 결국 앱이 전혀 확장 가능하지 않다는 것을 알게되었으므로 약간 자주 변경되는 모델의 경우 사용하는 쿼리가 끔찍하게 비효율적이기 때문에 관리자가 몇 달 안에 사용할 수 없게됩니다.
Cerin 2014 년

@Cerin 및 기타 : 여전히 사실입니까? 콘텐츠가 많은 사이트에 django-reversion을 사용할 수 있는지 확인하려고합니다. django-reversion은 djangopackages.org 및 SO 게시물에서 최고 등급 인 것 같지만 확장 가능 여부는 내 앱의 중요한 우선 순위이므로 다음과 같이 질문합니다.
Anupam

1
@Anupam, 프로덕션 사이트에서 비활성화해야했기 때문에 사용하지 않았습니다. 나는 문제를 버그로보고했지만 개발자가 나를 날려 버리고 문제가 아니라고 말했기 때문에 프로젝트를 재평가하지 않았습니다.
Cerin은

알겠습니다. 문제 링크를 공유해 주시겠습니까? 내 Django 앱에 사용할지 여부를 진지하게 고려하고 있기 때문에 매우 도움이 될 것입니다.
Anupam

3

예제 코드

여보세요,

최근에 서버 인벤토리 데이터베이스의 "업데이트"보기에 대한 로깅을 해킹했습니다. 내 "예제"코드를 공유 할 것이라고 생각했습니다. 다음 함수는 "서버"객체 중 하나, 변경된 항목 목록 및 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."
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.