Django 2.1 - Admin actions

प्रशासन की कार्रवाई




django

प्रशासन की कार्रवाई

Django के व्यवस्थापक का मूल वर्कफ़्लो, संक्षेप में, "किसी ऑब्जेक्ट का चयन करें, फिर उसे बदल दें।" यह अधिकांश उपयोग के मामलों के लिए अच्छी तरह से काम करता है। हालांकि, अगर आपको एक ही समय में कई वस्तुओं में समान परिवर्तन करने की आवश्यकता है, तो यह वर्कफ़्लो काफी थकाऊ हो सकता है।

इन मामलों में, Django के व्यवस्थापक आपको "क्रियाएं" लिखने और पंजीकृत करने की सुविधा देते हैं - सरल कार्य जो परिवर्तन सूची पृष्ठ पर चयनित वस्तुओं की सूची के साथ कहा जाता है।

यदि आप व्यवस्थापक की किसी भी परिवर्तन सूची को देखते हैं, तो आप इस सुविधा को कार्रवाई में देखेंगे; सभी मॉडलों के लिए उपलब्ध "हटाए गए ऑब्जेक्ट" कार्रवाई के साथ Django के जहाज। उदाहरण के लिए, यहाँ Django के अंतर्निहित django.contrib.auth ऐप से उपयोगकर्ता मॉड्यूल है।)

../../../_images/admin-actions.png

चेतावनी

"चयनित ऑब्जेक्ट हटाएं" कार्रवाई दक्षता कारणों के लिए QuerySet.delete() का उपयोग QuerySet.delete() है, जिसमें एक महत्वपूर्ण चेतावनी है: आपके मॉडल का delete() विधि नहीं कहा जाएगा।

यदि आप इस व्यवहार को ओवरराइड करना चाहते हैं, तो आप ModelAdmin.delete_queryset() को ओवरराइड कर सकते हैं या एक कस्टम एक्शन लिख सकते हैं जो आपके पसंदीदा तरीके से Model.delete() करता है - उदाहरण के लिए, प्रत्येक चयनित आइटम के लिए Model.delete() कॉल Model.delete()

बल्क विलोपन पर अधिक पृष्ठभूमि के लिए, ऑब्जेक्ट विलोपन पर प्रलेखन देखें।

इस सूची में अपने कार्यों को जोड़ने का तरीका जानने के लिए आगे पढ़ें।

लिखने की क्रिया

क्रियाओं को समझाने का सबसे आसान तरीका उदाहरण के रूप में है, तो आइए अंदर गोता लगाएँ।

व्यवस्थापक कार्यों के लिए एक सामान्य उपयोग मामला एक मॉडल का थोक अद्यतन है। एक Article मॉडल के साथ एक साधारण समाचार आवेदन की कल्पना करें:

from django.db import models

STATUS_CHOICES = (
    ('d', 'Draft'),
    ('p', 'Published'),
    ('w', 'Withdrawn'),
)

class Article(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
    status = models.CharField(max_length=1, choices=STATUS_CHOICES)

    def __str__(self):
        return self.title

एक सामान्य कार्य जो हम इस तरह से एक मॉडल के साथ कर सकते हैं, वह है "ड्राफ्ट" से "प्रकाशित" तक एक लेख की स्थिति को अपडेट करना। हम एक समय में व्यवस्थापक एक लेख में आसानी से ऐसा कर सकते थे, लेकिन अगर हम लेखों के एक समूह को थोक-प्रकाशित करना चाहते थे, तो यह बहुत कठिन होगा। तो, चलिए एक ऐसी कार्रवाई लिखते हैं, जो हमें "प्रकाशित" होने के लिए एक लेख की स्थिति बदलने देती है।

लेखन कार्य

सबसे पहले, हमें एक फ़ंक्शन लिखना होगा, जो तब मिलता है जब व्यवस्थापक से कार्रवाई शुरू हो जाती है। क्रिया कार्य केवल नियमित कार्य हैं जो तीन तर्क देते हैं:

  • वर्तमान ModelAdmin
  • एक HttpRequest वर्तमान अनुरोध का प्रतिनिधित्व करता है,
  • उपयोगकर्ता द्वारा चुनी गई वस्तुओं के सेट से युक्त एक QuerySet

हमारे प्रकाशित-इन-लेख फ़ंक्शन को ModelAdmin या अनुरोध ऑब्जेक्ट की आवश्यकता नहीं होगी, लेकिन हम ModelAdmin का उपयोग करेंगे:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')

ध्यान दें

सर्वश्रेष्ठ प्रदर्शन के लिए, हम क्वेरी की अपडेट पद्धति का उपयोग कर रहे हैं। अन्य प्रकार की क्रियाओं को व्यक्तिगत रूप से प्रत्येक वस्तु से निपटने की आवश्यकता हो सकती है; इन मामलों में हम क्वेरी पर बस पुनरावृति करेंगे:

for obj in queryset:
    do_something_with(obj)

यह वास्तव में एक कार्रवाई लिखने के लिए है! हालाँकि, हम एक और वैकल्पिक-उपयोगी कदम उठाएंगे और एक्शन को एडमिन में "अच्छा" शीर्षक देंगे। डिफ़ॉल्ट रूप से, यह क्रिया क्रिया सूची में "प्रकाशित करें" के रूप में दिखाई देगी - फ़ंक्शन नाम, अंडरस्कोर के साथ रिक्त स्थान द्वारा प्रतिस्थापित किया गया। यह ठीक है, लेकिन हम make_published फ़ंक्शन को make_published विशेषता देकर एक बेहतर, अधिक मानव-अनुकूल नाम प्रदान कर सकते हैं:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"

ध्यान दें

यह परिचित लग सकता है; व्यवस्थापक के list_display विकल्प का उपयोग उसी तकनीक का उपयोग करता है, जो वहां पंजीकृत कॉलबैक फ़ंक्शन के लिए मानव-पठनीय विवरण प्रदान करता है।

ModelAdmin क्रियाओं को जोड़ना

इसके बाद, हमें क्रिया के अपने ModelAdmin को सूचित करना ModelAdmin । यह किसी भी अन्य विन्यास विकल्प की तरह ही काम करता है। तो, कार्रवाई और इसके पंजीकरण के साथ पूरा admin.py

from django.contrib import admin
from myapp.models import Article

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"

class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'status']
    ordering = ['title']
    actions = [make_published]

admin.site.register(Article, ArticleAdmin)

वह कोड हमें एक व्यवस्थापक परिवर्तन सूची देगा जो कुछ इस तरह दिखता है:

../../../_images/adding-actions-to-the-modeladmin.png

यह वास्तव में वहाँ है! यदि आपको अपने स्वयं के कार्यों को लिखने में खुजली हो रही है, तो अब आप शुरू करने के लिए पर्याप्त जानते हैं। इस दस्तावेज़ के बाकी हिस्से में अधिक उन्नत तकनीकों को शामिल किया गया है।

कार्यों में त्रुटियों को संभालना

यदि आपकी कार्रवाई चलाते समय होने वाली त्रुटिपूर्ण त्रुटि स्थितियां हैं, तो आपको समस्या के उपयोगकर्ता को कृपापूर्वक सूचित करना चाहिए। इसका मतलब है कि अपवादों से निपटने और प्रतिक्रिया में समस्या के उपयोगकर्ता के अनुकूल विवरण को प्रदर्शित करने के लिए django.contrib.admin.ModelAdmin.message_user() का उपयोग django.contrib.admin.ModelAdmin.message_user()

उन्नत क्रिया तकनीक

अतिरिक्त विकल्पों और संभावनाओं की एक जोड़ी है जो आप अधिक उन्नत विकल्पों के लिए शोषण कर सकते हैं।

ModelAdmin तरीकों के रूप में क्रिया

ऊपर दिया गया उदाहरण make_published कार्रवाई को एक साधारण फ़ंक्शन के रूप में परिभाषित करता है। यह पूरी तरह से ठीक है, लेकिन यह कोड डिजाइन के दृष्टिकोण से बिल्कुल सही नहीं है: चूंकि कार्रवाई कसकर Article ऑब्जेक्ट को युग्मित करती है, इसलिए यह कार्रवाई को ArticleAdmin ऑब्जेक्ट को हुक करने के लिए समझ में आता है।

यह करना काफी आसान है:

class ArticleAdmin(admin.ModelAdmin):
    ...

    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.short_description = "Mark selected stories as published"

पहले ध्यान दें कि हमने make_published को एक विधि में बदल दिया है और modeladmin पैरामीटर को self बदल दिया है, और दूसरा कि हमने अब एक सीधा फ़ंक्शन संदर्भ के बजाय स्ट्रिंग 'make_published' actions में डाल दिया है। यह ModelAdmin को एक विधि के रूप में कार्रवाई को देखने के लिए कहता है।

विधियों के रूप में क्रियाओं को परिभाषित करना क्रिया को और अधिक सरल, ModelAdmin खुद को ModelAdmin तक ModelAdmin देता है, जिससे कार्रवाई व्यवस्थापक द्वारा प्रदान की गई किसी भी विधि को कॉल कर सकती है।

उदाहरण के लिए, हम उपयोगकर्ता को एक संदेश फ्लैश करने के लिए self का उपयोग कर सकते हैं जो उसे सूचित करता है कि कार्रवाई सफल थी:

class ArticleAdmin(admin.ModelAdmin):
    ...

    def make_published(self, request, queryset):
        rows_updated = queryset.update(status='p')
        if rows_updated == 1:
            message_bit = "1 story was"
        else:
            message_bit = "%s stories were" % rows_updated
        self.message_user(request, "%s successfully marked as published." % message_bit)

यह क्रिया से मेल खाता है जो किसी क्रिया को सफलतापूर्वक करने के बाद व्यवस्थापक स्वयं करता है:

../../../_images/actions-as-modeladmin-methods.png

ऐसे कार्य जो मध्यवर्ती पृष्ठ प्रदान करते हैं

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

एक मध्यस्थ पृष्ठ प्रदान करने के लिए, बस अपनी कार्रवाई से एक HttpResponse (या उपवर्ग) वापस कर दें। उदाहरण के लिए, आप एक साधारण निर्यात फ़ंक्शन लिख सकते हैं जो कि कुछ चयनित वस्तुओं को JSON के रूप में डंप करने के लिए Django के क्रमांकन कार्यों का उपयोग करता है:

from django.core import serializers
from django.http import HttpResponse

def export_as_json(modeladmin, request, queryset):
    response = HttpResponse(content_type="application/json")
    serializers.serialize("json", queryset, stream=response)
    return response

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

from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect

def export_selected_objects(modeladmin, request, queryset):
    selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
    ct = ContentType.objects.get_for_model(queryset.model)
    return HttpResponseRedirect("/export/?ct=%s&ids=%s" % (ct.pk, ",".join(selected)))

जैसा कि आप देख सकते हैं, कार्रवाई सरल हिस्सा है; सभी जटिल तर्क आपके निर्यात दृश्य में होंगे। इसके लिए किसी भी प्रकार की वस्तुओं से निपटने की आवश्यकता होगी, इसलिए सामग्री के साथ व्यापार।

इस दृश्य को लिखना पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है।

साइट-व्यापी कार्य उपलब्ध कराना

AdminSite.add_action(action, name=None) [source]

कुछ क्रियाएं सबसे अच्छी होती हैं यदि उन्हें व्यवस्थापक साइट के किसी भी ऑब्जेक्ट के लिए उपलब्ध कराया जाता है - ऊपर परिभाषित निर्यात कार्रवाई एक अच्छा उम्मीदवार होगा। आप AdminSite.add_action() का उपयोग करके विश्व स्तर पर उपलब्ध कार्रवाई कर सकते हैं। उदाहरण के लिए:

from django.contrib import admin

admin.site.add_action(export_selected_objects)

यह export_selected_objects कार्रवाई को "Export_selected_objects" नामक एक कार्रवाई के रूप में विश्व स्तर पर उपलब्ध कराता है। आप कार्रवाई को स्पष्ट रूप से एक नाम दे सकते हैं - अच्छा यदि आप बाद में प्रोग्राम को कार्रवाई को हटाना चाहते हैं - AdminSite.add_action() लिए दूसरा तर्क पारित करके:

admin.site.add_action(export_selected_objects, 'export_selected')

क्रियाओं को अक्षम करना

कभी-कभी आपको कुछ कार्यों को अक्षम करने की आवश्यकता होती है - विशेष रूप से उन पंजीकृत साइट- विशेष वस्तुओं के लिए। कुछ तरीके हैं जिनसे आप क्रियाओं को निष्क्रिय कर सकते हैं:

साइट-व्यापी कार्रवाई अक्षम करना

AdminSite.disable_action(name) [source]

यदि आपको साइट-वाइड एक्शन को अक्षम करने की आवश्यकता है, तो आप AdminSite.disable_action() को कॉल कर सकते हैं।

उदाहरण के लिए, आप अंतर्निहित "हटाए गए ऑब्जेक्ट" कार्रवाई को हटाने के लिए इस पद्धति का उपयोग कर सकते हैं:

admin.site.disable_action('delete_selected')

एक बार जब आपने उपरोक्त कार्य कर लिया, तो वह क्रिया अब साइट पर उपलब्ध नहीं होगी।

यदि, हालांकि, आपको किसी विशेष मॉडल के लिए वैश्विक रूप से अक्षम कार्रवाई को फिर से सक्षम करने की आवश्यकता है, तो बस इसे स्पष्ट रूप से अपनी ModelAdmin.actions सूची में सूचीबद्ध करें:

# Globally disable delete selected
admin.site.disable_action('delete_selected')

# This ModelAdmin will not have delete_selected available
class SomeModelAdmin(admin.ModelAdmin):
    actions = ['some_other_action']
    ...

# This one will
class AnotherModelAdmin(admin.ModelAdmin):
    actions = ['delete_selected', 'a_third_action']
    ...

किसी विशेष ModelAdmin लिए सभी कार्यों को अक्षम ModelAdmin

यदि आप किसी दिए गए ModelAdmin लिए कोई बल्क क्रियाएँ उपलब्ध नहीं चाहते हैं, तो ModelAdmin.actions को None को None सेट ModelAdmin.actions करें:

class MyModelAdmin(admin.ModelAdmin):
    actions = None

यह ModelAdmin को किसी भी साइट-वाइड एक्शन सहित किसी भी एक्शन को प्रदर्शित या अनुमति नहीं देता है।

सक्रिय रूप से क्रियाओं को सक्षम या अक्षम करना

ModelAdmin.get_actions(request) [source]

अंत में, आप ModelAdmin.get_actions() को ओवरराइड करके, प्रति-अनुरोध (और इसलिए प्रति-उपयोगकर्ता आधार) पर सशर्त रूप से सक्षम या अक्षम कर सकते हैं।

यह अनुमत क्रियाओं का शब्दकोश देता है। कुंजियाँ क्रिया नाम हैं, और मान हैं (function, name, short_description) ट्यूपल्स।

अधिकांश समय आप इस विधि का उपयोग सशर्त रूप से एकत्रित की गई सूची से सशर्त रूप से हटाने के लिए करेंगे। उदाहरण के लिए, यदि मैं केवल उन उपयोगकर्ताओं को चाहता हूं जिनके नाम 'J' से शुरू होते हैं, जो बल्क में वस्तुओं को हटाने में सक्षम होते हैं, तो मैं निम्नलिखित कर सकता हूं:

class MyModelAdmin(admin.ModelAdmin):
    ...

    def get_actions(self, request):
        actions = super().get_actions(request)
        if request.user.username[0].upper() != 'J':
            if 'delete_selected' in actions:
                del actions['delete_selected']
        return actions

क्रियाओं के लिए अनुमतियाँ सेट करना

Django 2.1 में नया:

कार्रवाई कार्य पर कार्य करने की अनुमति के लिए विशिष्ट अनुमतियों वाले उपयोगकर्ताओं के लिए उनकी उपलब्धता को सीमित कर सकती है:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.allowed_permissions = ('change',)

make_published() क्रिया केवल उन उपयोगकर्ताओं के लिए उपलब्ध होगी जो ModelAdmin.has_change_permission() चेक पास करते हैं।

यदि allowed_permissions में एक से अधिक अनुमति हैं, तो कार्रवाई तब तक उपलब्ध होगी जब तक उपयोगकर्ता कम से कम एक चेक पास नहीं करता।

allowed_permissions मानों के लिए उपलब्ध मूल्य और इसी विधि जाँच हैं:

जब तक आप किसी संगत has_<value>_permission(self, request) पद्धति को ModelAdmin पर लागू करते हैं, तब तक आप कोई अन्य मान निर्दिष्ट कर सकते हैं।

उदाहरण के लिए:

from django.contrib import admin
from django.contrib.auth import get_permission_codename

class ArticleAdmin(admin.ModelAdmin):
    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.allowed_permissions = ('publish',)

    def has_publish_permission(self, request):
        """Does the user have the publish permission?"""
        opts = self.opts
        codename = get_permission_codename('publish', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))