Django व्यवस्थापक के मॉडल इतिहास में बांधना


93

स्थापित करना:

  • मैं एक Django एप्लिकेशन पर काम कर रहा हूं जो उपयोगकर्ताओं को डेटाबेस में एक ऑब्जेक्ट बनाने की अनुमति देता है और फिर वापस जाता है और इसे संपादित करता है जितना वे चाहते हैं।
  • Django की एडमिन साइट, एडमिन साइट के माध्यम से ऑब्जेक्ट में किए गए बदलावों का इतिहास रखती है।

प्रश्न:

  • मैं अपने आवेदन को व्यवस्थापक साइट के परिवर्तन के इतिहास पर कैसे हुक कर सकता हूं ताकि मैं उन परिवर्तनों के इतिहास को देख सकूं जो उपयोगकर्ता अपनी "सामग्री" में करते हैं?

जवाबों:


133

व्यवस्थापक इतिहास किसी भी अन्य Django ऐप की तरह ही एक ऐप है, अपवाद के साथ एडमिन साइट पर विशेष प्लेसमेंट है।

मॉडल django.contrib.admin.models.ogEntry में है।

जब कोई उपयोगकर्ता कोई परिवर्तन करता है, तो लॉग को इस तरह जोड़ें (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वह वस्तु कहां है जो निश्चित रूप से बदली गई थी।

अब मैं डैनियल का जवाब देखता हूं और उससे सहमत हूं, यह बहुत सीमित है।

मेरी राय में अपनी पुस्तक प्रो Django में मार्टी अल्चिन से कोड का उपयोग करने के लिए एक मजबूत दृष्टिकोण है ( पेज 263 पर शुरू होने वाले ऐतिहासिक रिकॉर्ड रखना देखें )। एक अनुप्रयोग django-simple-history है, जो इस दृष्टिकोण को लागू करता है और विस्तारित करता है ( डॉक्स यहाँ )।


7
मत भूलो: django.contrib.contenttypes.models से ContentType आयात करें। इसके अलावा, Force_unicode भी उनका अपना कार्य है।
साकबाको

10
from django.utils.encoding import force_unicode'फोर्स_सुकोड' के लिए
एमएमआरएस 151

17
चूँकि इस प्रश्न का उत्तर दिया गया था, मार्टी अल्चिन के दृष्टिकोण को खुला और एक आवेदन में विस्तारित किया गया है जिसे django-simple-history कहा जाता है ।
ट्रे हुनर

5
Django-simple-history का नया घर लगता है: github.com/treyhunner/django-simple-history RTD पर अधिक जानकारी django-simple-history.readthedocs.org/en/latest
Brutus

3
एक अच्छा दृष्टिकोण djangopackages.com पर तुलना ग्रिड की जांच करने के लिए भी हो सकता है जहां django-simple-history और अन्य समाधान (जैसे CleanerVersion या django-reversion) की तुलना की जाती है।
मेनेल

21

व्यवस्थापक का इतिहास परिवर्तन लॉग में परिभाषित किया गया है django.contrib.admin.models, और history_viewमानक ModelAdminवर्ग में एक विधि है ।

हालांकि वे विशेष रूप से चालाक नहीं हैं, और काफी कसकर प्रशासक से जुड़े हैं, इसलिए आप केवल विचारों के लिए इनका उपयोग कर सकते हैं और अपने ऐप के लिए अपना संस्करण बना सकते हैं।


4
क्या यह अभी भी सच है?
यहाँ

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})

जैसा कि उपरोक्त कोड स्निपेट में देखा गया है, मैं 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-प्रत्यावर्तन नामक एक ऐप के साथ काम कर रहा हूं, जो कि 'the हुकुम' को इतिहास में शामिल करता है और वास्तव में इसमें जुड़ जाता है। यदि आप कुछ नमूना कोड चाहते हैं जो देखने के लिए एक अच्छी जगह होगी।

(2) यदि आपने अपनी खुद की इतिहास कार्यक्षमता को रोल करने का निर्णय लिया है तो django सिग्नल देता है कि आप अपने ऐप को हैंडल करने के लिए सदस्यता ले सकते हैं, उदाहरण के लिए, प्रत्येक इतिहास ऑब्जेक्ट के लिए post_save। आपका कोड हर बार इतिहास लॉग प्रविष्टि सहेजे जाने पर चलेगा। Doc: Django सिग्नल


3
मैं django- प्रत्यावर्तन के खिलाफ दृढ़ता से सिफारिश करूंगा । अवधारणा में, यह एक महान विचार है, लेकिन कार्यान्वयन भयानक है। मैंने इसे एक प्रोडक्शन साइट में इस्तेमाल किया और यह एक बुरा सपना था। इसने पहली बार बहुत अच्छा काम किया, लेकिन मुझे अंततः पता चला कि ऐप सभी स्केलेबल पर नहीं है, इसलिए अर्ध-लगातार बदलाव वाले किसी भी मॉडल के लिए, आपका व्यवस्थापक कुछ महीनों में अनुपयोगी हो जाएगा क्योंकि इसमें उपयोग किए जाने वाले प्रश्न बहुत ही अक्षम हैं।
सेरिन

@ कैरिन और अन्य: क्या यह अभी भी सच है? मैं यह देखने की कोशिश कर रहा हूं कि क्या मैं बहुत सी सामग्री वाली साइट के लिए django-reversion का उपयोग कर सकता हूं। django-reversion djangopackages.org और SO पोस्ट पर टॉप-रेटेड लगता है, लेकिन सक्षम होना-टू-स्केल मेरे ऐप के लिए एक महत्वपूर्ण प्राथमिकता है, इसलिए पूछना
अनुपम

1
@ अनुपम, मैंने इसका इस्तेमाल नहीं किया है क्योंकि मुझे इसे अपने प्रोडक्शन साइट से डिसेबल करना था। मैंने समस्याओं को बग के रूप में रिपोर्ट किया, लेकिन देव ने मुझे उड़ा दिया और कहा कि यह कोई समस्या नहीं थी, इसलिए मैंने परियोजना का पुनर्मूल्यांकन नहीं किया है।
सेरिन

मैं देख रहा हूँ - क्या आपको मुद्दा लिंक साझा करने का मन है? मेरे लिए सुपर सहायक होगा क्योंकि मैं गंभीरता से इस बात पर विचार कर रहा हूं कि इसका उपयोग करना है या नहीं, मेरे Django ऐप के लिए
अनुपम

3

उदाहरण कोड

हैलो,

मैंने हाल ही में हमारे सर्वर इन्वेंट्री डेटाबेस के लिए "अपडेट" दृश्य में कुछ लॉगिंग में हैक किया। मुझे लगा कि मैं अपना "उदाहरण" कोड साझा करूंगा। फ़ंक्शन जो अनुसरण करता है वह हमारी "सर्वर" वस्तुओं में से एक को लेता है, उन चीजों की एक सूची जो बदल दी गई है, और एक्शन या चेंज का एक एक्शन_फ्लैग। यह उन चीजों को सरल करता है, जहां एडी का अर्थ "एक नया सर्वर जोड़ा गया" है। एक अधिक लचीला दृष्टिकोण एक सर्वर में एक विशेषता जोड़ने के लिए अनुमति देगा। बेशक, यह निर्धारित करने के लिए हमारे मौजूदा कार्यों को ऑडिट करने के लिए पर्याप्त रूप से चुनौतीपूर्ण था कि क्या वास्तव में एक बदलाव हुआ था, इसलिए मैं "परिवर्तन" के रूप में नई विशेषताओं को लॉग इन करने के लिए पर्याप्त खुश हूं।

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."
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.