Django 2.1 - Using mixins with class-based views

वर्ग-आधारित विचारों के साथ मिश्रण का उपयोग करना




django

वर्ग-आधारित विचारों के साथ मिश्रण का उपयोग करना

सावधान

यह एक उन्नत विषय है। इन तकनीकों की खोज करने से पहले Django के क्लास-आधारित विचारों का एक कार्यसाधक ज्ञान की सलाह दी जाती है।

Django के बिल्ट-इन क्लास-आधारित विचार बहुत अधिक कार्यक्षमता प्रदान करते हैं, लेकिन इसमें से कुछ आप अलग से उपयोग करना चाह सकते हैं। उदाहरण के लिए, आप एक ऐसा दृश्य लिखना चाह सकते हैं जो HTTP प्रतिसाद बनाने के लिए एक टेम्पलेट प्रदान करता है, लेकिन आप TemplateView उपयोग नहीं कर सकते हैं; शायद आपको केवल POST पर एक टेम्पलेट रेंडर करने की आवश्यकता है, जिसमें GET पूरी तरह से कुछ और कर सकता है। जब आप सीधे TemplateResponse रिप्रेंट का उपयोग कर सकते हैं, तो इसका परिणाम डुप्लिकेट कोड में होगा।

इस कारण से, Django भी कई मिश्रण प्रदान करता है जो अधिक असतत कार्यक्षमता प्रदान करते हैं। उदाहरण के लिए, टेम्पलेट रेंडरिंग को TemplateResponseMixin में समझाया गया है। Django संदर्भ दस्तावेज में सभी मिश्रणों का पूर्ण प्रलेखन शामिल है।

संदर्भ और टेम्पलेट प्रतिक्रियाएँ

दो केंद्रीय मिश्रण प्रदान किए जाते हैं जो क्लास-आधारित विचारों में टेम्पलेट्स के साथ काम करने के लिए एक सुसंगत इंटरफ़ेस प्रदान करने में मदद करते हैं।

TemplateResponseMixin

हरेक दृश्य में बनाया गया है, जो एक TemplateResponse लौटाता है, जो render_to_response() विधि को कहता है जो TemplateResponseMixin प्रदान करता है। अधिकांश समय यह आपके लिए बुलाया जाएगा (उदाहरण के लिए, इसे TemplateView और DetailView दोनों द्वारा लागू किया गया get() विधि द्वारा बुलाया जाता है; इसी तरह, यह संभावना नहीं है कि आपको इसे ओवरराइड करने की आवश्यकता होगी, हालांकि यदि आप चाहते हैं कि आपकी प्रतिक्रिया किसी Django टेम्पलेट के माध्यम से प्रदान नहीं की गई है, तो आप इसे करना चाहते हैं। इसके एक उदाहरण के लिए, JSONResponseMixin उदाहरण देखें।

render_to_response() खुद को get_template_names() कहता है, जो डिफ़ॉल्ट रूप से सिर्फ क्लास-आधारित दृश्य पर template_name दिखेगा; दो अन्य मिश्रण ( SingleObjectTemplateResponseMixin और MultipleObjectTemplateResponseMixin ) वास्तविक वस्तुओं से निपटने के दौरान अधिक लचीली चूक प्रदान करने के लिए इसे ओवरराइड करते हैं।

ContextMixin
प्रत्येक निर्मित दृश्य जिसे संदर्भ डेटा की आवश्यकता होती है, जैसे कि टेम्प्लेट को रेंडर करने के लिए (ऊपर TemplateResponseMixin सहित), get_context_data() किसी भी ऐसे डेटा को पास करना चाहिए जिसे वे सुनिश्चित करना चाहते हैं कि इसमें कीवर्ड तर्क हैं। get_context_data() एक शब्दकोश देता है; ContextMixin यह केवल अपने कीवर्ड के तर्क देता है, लेकिन शब्दकोश में अधिक सदस्यों को जोड़ने के लिए इसे ओवरराइड करना आम है। आप extra_context विशेषता का भी उपयोग कर सकते हैं।

Django के सामान्य वर्ग-आधारित विचारों का निर्माण

आइए देखें कि कैसे दो Django के सामान्य वर्ग-आधारित विचार असतत कार्यक्षमता प्रदान करने वाले मिश्रणों से बने हैं। हम विस्तार से विचार DetailView , जो किसी ऑब्जेक्ट के "विस्तार" दृश्य को प्रस्तुत करता है, और ListView , जो वस्तुओं की एक सूची प्रदान करेगा, आमतौर पर एक क्वेरी से, और वैकल्पिक रूप से उन्हें पृष्ठांकित करें। यह हमें चार मिक्सिंस से परिचित कराएगा, जो दोनों में से किसी एक Django ऑब्जेक्ट, या कई ऑब्जेक्ट्स के साथ काम करते समय उपयोगी कार्यक्षमता प्रदान करते हैं।

जेनेरिक एडिट व्यूज ( FormView , और मॉडल-विशिष्ट व्यू UpdateView , UpdateView और DeleteView ) में, और डेट-बेस्ड जेनेरिक व्यूज में भी DeleteView हैं। ये मिक्सिन रेफरेंस डॉक्यूमेंटेशन में कवर किए गए हैं

DetailView : एक एकल Django ऑब्जेक्ट के साथ काम करना

किसी वस्तु के विस्तार को दिखाने के लिए, हमें मूल रूप से दो काम करने की आवश्यकता है: हमें वस्तु को देखने की आवश्यकता है और फिर हमें एक उपयुक्त टेम्पलेट के साथ एक TemplateResponse बनाने की आवश्यकता है, और वह वस्तु संदर्भ के रूप में है।

ऑब्जेक्ट प्राप्त करने के लिए, DetailView पर निर्भर करता है, जो एक get_object() विधि प्रदान करता है जो ऑब्जेक्ट को अनुरोध के URL पर आधारित करता है (यह URLConf में घोषित के रूप में pk और slug कीवर्ड दलीलों की तलाश करता है, और ऑब्जेक्ट को या तो देखता है। दृश्य पर model विशेषता से, या queryset विशेषता यदि प्रदान की गई है)। SingleObjectMixin भी get_context_data() ओवरराइड करता है, जिसका उपयोग टेम्पलेट रेंडर के लिए संदर्भ डेटा की आपूर्ति करने के लिए क्लास-आधारित विचारों में निर्मित सभी Django के पार किया जाता है।

फिर एक TemplateResponse बनाने के लिए, DetailView , DetailView का उपयोग करता है, जो TemplateResponseMixin विस्तार करता है, जो get_template_names() रूप में ऊपर चर्चा की गई है। यह वास्तव में विकल्पों का एक काफी परिष्कृत सेट प्रदान करता है, लेकिन मुख्य जो कि ज्यादातर लोग उपयोग करने जा रहे हैं वह है <app_label>/<model_name>_detail.html_detail भाग को उपवर्ग पर template_name_suffix _detail पर सेट करके कुछ और में बदला जा सकता है। (उदाहरण के लिए, जेनेरिक एडिट व्यू _form बनाने और अपडेट के लिए _form उपयोग करते हैं, और _confirm_delete लिए _confirm_delete )

ListView : कई Django ऑब्जेक्ट्स के साथ काम करना

वस्तुओं की सूची लगभग एक ही पैटर्न का अनुसरण करती है: हमें वस्तुओं की सूची (संभवतः पृष्ठांकित) की आवश्यकता होती है, आमतौर पर एक QuerySet , और फिर हमें वस्तुओं की उस सूची का उपयोग करके एक उपयुक्त टेम्पलेट के साथ एक TemplateResponse बनाने की आवश्यकता होती है।

ऑब्जेक्ट प्राप्त करने के लिए, ListView का उपयोग करता है, जो दोनों get_queryset() और paginate_queryset() प्रदान करता है। SingleObjectMixin विपरीत, साथ काम करने के लिए SingleObjectMixin का पता लगाने के लिए URL के कुछ हिस्सों को बंद करने की कोई आवश्यकता नहीं है, इसलिए डिफ़ॉल्ट बस व्यू क्लास पर queryset या model विशेषता का उपयोग करता है। get_queryset() को ओवरराइड करने का एक सामान्य कारण यहां वस्तुओं को गतिशील रूप से अलग-अलग करना होगा, जैसे कि वर्तमान उपयोगकर्ता पर निर्भर करता है या भविष्य में ब्लॉग के लिए पोस्ट को बाहर करना है।

MultipleObjectMixin get_context_data() भी get_context_data() लिए उपयुक्त संदर्भ चरों को शामिल करने के लिए get_context_data() को ओवरराइड get_context_data() होने पर डमी प्रदान करता है)। यह एक कीवर्ड तर्क के रूप में पारित होने वाले object_list पर निर्भर करता है, जिसे ListView व्यू इसके लिए व्यवस्थित करता है।

TemplateResponse बनाने के लिए, ListView तब MultipleObjectTemplateResponseMixin का उपयोग करता है; जैसा कि ऊपर दिए गए SingleObjectTemplateResponseMixin साथ, इस MultipleObjectTemplateResponseMixin प्रदान करने के लिए get_template_names() ओवरराइड get_template_names() , सबसे अधिक इस्तेमाल किया जा रहा है के साथ <app_label>/<model_name>_list.html , _list भाग के साथ फिर से template_name_suffix विशेषता से लिया जाता है। (दिनांक आधारित सामान्य विचार प्रत्यय का उपयोग करते हैं जैसे कि _archive , _archive_year और इसी तरह विभिन्न विशिष्ट तिथि-आधारित सूची दृश्यों के लिए विभिन्न टेम्पलेट्स का उपयोग करने के लिए।)

Django के वर्ग-आधारित दृश्य मिश्रण का उपयोग करना

अब हमने देखा कि कैसे Django के सामान्य वर्ग-आधारित विचार प्रदान किए गए मिश्रणों का उपयोग करते हैं, आइए हम उन अन्य तरीकों को देखें जिन्हें हम उन्हें जोड़ सकते हैं। बेशक हम अभी भी उन्हें बिल्ट-इन क्लास-आधारित विचारों, या अन्य जेनेरिक क्लास-आधारित विचारों के साथ जोड़ रहे हैं, लेकिन कई दुर्लभ समस्याएं हैं जिन्हें आप हल कर सकते हैं जैसे कि Django द्वारा बॉक्स के बाहर प्रदान किया गया है। ।

चेतावनी

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

Django के क्लास-आधारित विचारों और क्लास-आधारित दृश्य मिश्रणों के लिए संदर्भ प्रलेखन आपको यह समझने में मदद करेगा कि विभिन्न वर्गों और मिश्रणों के बीच किन विशेषताओं और विधियों के कारण संघर्ष होने की संभावना है।

यदि संदेह है, तो अक्सर View या TemplateView View पर अपने काम का बैक अप लेना बेहतर होता है, शायद SingleObjectMixin और SingleObjectMixin साथ। हालाँकि आप शायद अधिक कोड लिखना समाप्त कर देंगे, लेकिन बाद में किसी और के लिए इसे स्पष्ट रूप से समझने की संभावना अधिक है, और आपके बारे में चिंता करने के लिए कम बातचीत के साथ अपने आप को कुछ सोच को बचाएगा। (बेशक, आप हमेशा समस्याओं से निपटने के लिए प्रेरणा के लिए सामान्य वर्ग-आधारित विचारों के Django के कार्यान्वयन में डुबकी लगा सकते हैं।)

दृश्य के साथ SingleObjectMixin का उपयोग करना

यदि हम एक साधारण वर्ग-आधारित दृश्य लिखना चाहते हैं, जो केवल POST प्रतिक्रिया करता है, तो हम उप-वर्ग में एक post() विधि View और लिखेंगे। हालाँकि, अगर हम चाहते हैं कि हमारा संसाधन URL से पहचाने जाने वाले किसी विशेष ऑब्जेक्ट पर काम करे, तो हम SingleObjectMixin द्वारा प्रदान की गई कार्यक्षमता चाहते हैं।

हम इसे सामान्य वर्ग-आधारित विचारों के परिचय में उपयोग किए गए Author मॉडल के साथ प्रदर्शित करेंगे।

from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.urls import reverse
from django.views import View
from django.views.generic.detail import SingleObjectMixin
from books.models import Author

class RecordInterest(SingleObjectMixin, View):
    """Records the current user's interest in an author."""
    model = Author

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()

        # Look up the author we're interested in.
        self.object = self.get_object()
        # Actually record interest somehow here!

        return HttpResponseRedirect(reverse('author-detail', kwargs={'pk': self.object.pk}))

व्यवहार में, आप संभवतः एक रिलेशनल डेटाबेस के बजाय एक कुंजी-मूल्य स्टोर में रुचि रिकॉर्ड करना चाहते हैं, इसलिए हमने उस बिट को छोड़ दिया है। SingleObjectMixin का उपयोग करने के बारे में चिंता करने की जरूरत है कि केवल एक ही दृश्य है जहां हम उस लेखक को देखना चाहते हैं जिसे हम रुचि रखते हैं, जो कि यह self.get_object() लिए एक साधारण कॉल के साथ करता है। मिक्सचर द्वारा हमारे लिए अन्य सभी चीजों का ध्यान रखा जाता है।

हम इसे आसानी से पर्याप्त रूप से अपने URL में हुक कर सकते हैं:

from django.urls import path
from books.views import RecordInterest

urlpatterns = [
    #...
    path('author/<int:pk>/interest/', RecordInterest.as_view(), name='author-interest'),
]

Author उदाहरण को देखने के लिए get_object() का उपयोग करने वाले pk नाम के समूह पर ध्यान दें। आप एक स्लग, या SingleObjectMixin की किसी भी अन्य विशेषता का SingleObjectMixin

ListView साथ SingleObjectMixin का उपयोग करना

लिस्ट व्यू बिल्ट-इन ListView प्रदान करता है, लेकिन आप उन वस्तुओं की एक सूची बनाना चाहते हैं, जो किसी अन्य वस्तु से (एक विदेशी कुंजी द्वारा) जुड़ी हुई हैं। हमारे प्रकाशन उदाहरण में, आप किसी विशेष प्रकाशक द्वारा सभी पुस्तकों के माध्यम से पृष्ठांकित करना चाह सकते हैं।

ऐसा करने का एक तरीका है, SingleObjectMixin को SingleObjectMixin साथ SingleObjectMixin , ताकि पुस्तकों की पृष्ठांकित सूची के लिए SingleObjectMixin एकल ऑब्जेक्ट के रूप में पाए गए प्रकाशक को लटका सकें। ऐसा करने के लिए, हमारे पास दो अलग-अलग क्वेरीज़ होने चाहिए:

ListView Book queryset for use by
चूँकि हमारे पास Publisher पहुँच है, जिनकी पुस्तकों को हम सूचीबद्ध करना चाहते हैं, हम बस get_queryset() ओवरराइड करते हैं और Publisher के रिवर्स विदेशी कुंजी प्रबंधक का उपयोग करते हैं।
get_object() Publisher queryset for use in get_object()
हम सही Publisher वस्तु प्राप्त करने के लिए get_object() के डिफ़ॉल्ट कार्यान्वयन पर भरोसा करेंगे। हालाँकि, हमें स्पष्ट रूप से एक queryset तर्क पास करने की आवश्यकता है क्योंकि अन्यथा get_object() का डिफ़ॉल्ट कार्यान्वयन get_object() जिसे हमने Publisher बजाय Book ऑब्जेक्ट वापस करने के लिए ओवरराइड किया है।

ध्यान दें

हमें get_context_data() बारे में सावधानी से सोचना होगा। चूंकि SingleObjectMixin और ListView दोनों SingleObjectMixin के मान के तहत संदर्भ डेटा में चीजें SingleObjectMixin , अगर यह सेट है, तो हम स्पष्ट रूप से यह सुनिश्चित करेंगे कि Publisher संदर्भ डेटा में है। ListView हमारे लिए उपयुक्त page_obj और page_obj कि हम super() को कॉल करना याद रखें super()

अब हम एक नया PublisherDetail लिख सकते हैं:

from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from books.models import Publisher

class PublisherDetail(SingleObjectMixin, ListView):
    paginate_by = 2
    template_name = "books/publisher_detail.html"

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=Publisher.objects.all())
        return super().get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['publisher'] = self.object
        return context

    def get_queryset(self):
        return self.object.book_set.all()

ध्यान दें कि हम कैसे get() भीतर self.object सेट self.object हैं, इसलिए हम इसे बाद में get_context_data() और get_context_data() में फिर से उपयोग कर सकते हैं। यदि आप template_name सेट नहीं करते हैं, तो टेम्पलेट सामान्य ListView विकल्प को डिफ़ॉल्ट करेगा, जो इस मामले में "books/book_list.html" क्योंकि यह पुस्तकों की सूची है; SingleObjectMixin बारे में कुछ भी नहीं पता है, इसलिए इसका कोई सुराग नहीं है कि यह Publisher साथ कुछ भी करना है।

paginate_by जानबूझकर उदाहरण में छोटा है इसलिए आपको पेजेशन काम करने के लिए बहुत सारी किताबें बनाने की ज़रूरत नहीं है! यहां वह टेम्पलेट है जिसका आप उपयोग करना चाहते हैं:

{% extends "base.html" %}

{% block content %}
    <h2>Publisher {{ publisher.name }}</h2>

    <ol>
      {% for book in page_obj %}
        <li>{{ book.title }}</li>
      {% endfor %}
    </ol>

    <div class="pagination">
        <span class="step-links">
            {% if page_obj.has_previous %}
                <a href="?page={{ page_obj.previous_page_number }}">previous</a>
            {% endif %}

            <span class="current">
                Page {{ page_obj.number }} of {{ paginator.num_pages }}.
            </span>

            {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}">next</a>
            {% endif %}
        </span>
    </div>
{% endblock %}

कुछ भी अधिक जटिल से बचें

आम तौर पर आप TemplateResponseMixin और SingleObjectMixin उपयोग कर सकते हैं जब आपको उनकी कार्यक्षमता की आवश्यकता होती है। जैसा कि ऊपर दिखाया गया है, थोड़ी सी देखभाल के साथ आप SingleObjectMixin साथ SingleObjectMixin को भी जोड़ ListView । हालाँकि चीजें इतनी जटिल हो जाती हैं कि आप ऐसा करने की कोशिश करते हैं, और अंगूठे का एक अच्छा नियम है:

संकेत

आपके प्रत्येक दृश्य को सामान्य वर्ग-आधारित विचारों के समूहों में से एक से केवल मिक्सिन या विचारों का उपयोग करना चाहिए: विस्तार, सूची , संपादन और दिनांक। उदाहरण के लिए, यह SingleObjectMixin (जेनेरिक सूची) के साथ TemplateView (दृश्य में निर्मित) को संयोजित करने के लिए ठीक है, लेकिन आपको SingleObjectMixin (जेनेरिक डिटेल) के साथ MultipleObjectMixin (जेनेरिक सूची) के संयोजन में समस्या होने की संभावना है।

यह दिखाने के लिए कि जब आप अधिक परिष्कृत होने की कोशिश करते हैं, तो हम एक उदाहरण दिखाते हैं कि जब एक सरल समाधान होता है, तो पठनीयता और स्थिरता का बलिदान होता है। सबसे पहले, आइए एक FormMixin से एक Django Form को URL के रूप में हमें सक्षम करने के लिए DetailView साथ FormMixin को संयोजित करने के लिए एक भोले प्रयास के रूप में देखें, क्योंकि हम एक ऑब्जेक्ट का उपयोग करके प्रदर्शित कर रहे हैं।

FormMixin का उपयोग FormMixin साथ DetailView

View और SingleObjectMixin एक साथ उपयोग करने के हमारे पहले उदाहरण पर SingleObjectMixin करें। हम एक विशेष लेखक में उपयोगकर्ता की रुचि दर्ज कर रहे थे; अब यह कहें कि हम उन्हें यह कहते हुए एक संदेश छोड़ना चाहते हैं कि वे उन्हें क्यों पसंद करते हैं। फिर से, मान लें कि हम इसे एक रिलेशनल डेटाबेस में स्टोर करने नहीं जा रहे हैं, बल्कि इसके बजाय कुछ और गूढ़ है कि हम यहाँ के बारे में चिंता नहीं करेंगे।

इस बिंदु पर उपयोगकर्ता के ब्राउज़र से Django के लिए भेजी गई जानकारी को एनकोड करने के लिए Form लिए पहुंचना स्वाभाविक है। यह भी कहें कि हम REST में भारी निवेश कर रहे हैं, इसलिए हम उपयोगकर्ता से संदेश कैप्चर करने के लिए लेखक को प्रदर्शित करने के लिए उसी URL का उपयोग करना चाहते हैं। आइए ऐसा करने के लिए हमारे AuthorDetailView को फिर से AuthorDetailView

हम GET को DetailView से संभाल कर DetailView , हालाँकि हमें संदर्भ डेटा में एक Form जोड़ना होगा ताकि हम इसे टेम्पलेट में रेंडर कर सकें। हम FormMixin से फॉर्म प्रोसेसिंग में भी खींचना चाहते हैं, और थोड़ा सा कोड लिखेंगे ताकि POST पर फॉर्म को उचित रूप से बुलाया जा सके।

ध्यान दें

हम FormMixin उपयोग FormMixin और FormView (जो पहले से ही उपयुक्त post() प्रदान करता है post() साथ DetailView को मिलाने के बजाय post() स्वयं लागू करते हैं क्योंकि दोनों दृश्य लागू होते get() , और चीजें बहुत अधिक भ्रमित हो जाएंगी।

हमारा नया AuthorDetail इस तरह दिखता है:

# CAUTION: you almost certainly do not want to do this.
# It is provided as part of a discussion of problems you can
# run into when combining different generic class-based view
# functionality that is not designed to be used together.

from django import forms
from django.http import HttpResponseForbidden
from django.urls import reverse
from django.views.generic import DetailView
from django.views.generic.edit import FormMixin
from books.models import Author

class AuthorInterestForm(forms.Form):
    message = forms.CharField()

class AuthorDetail(FormMixin, DetailView):
    model = Author
    form_class = AuthorInterestForm

    def get_success_url(self):
        return reverse('author-detail', kwargs={'pk': self.object.pk})

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.get_form()
        return context

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        # Here, we would record the user's interest using the message
        # passed in form.cleaned_data['message']
        return super().form_valid(form)

get_success_url() बस कहीं न कहीं पुनर्निर्देशित करने के लिए प्रदान कर रहा है, जो कि form_valid() के डिफ़ॉल्ट कार्यान्वयन में उपयोग किया जाता है। हमें अपने स्वयं के post() पहले get_context_data() गए अनुसार उपलब्ध कराने get_context_data() , और संदर्भ डेटा में Form उपलब्ध कराने के लिए get_context_data() ओवरराइड करना होगा।

एक बेहतर उपाय

यह स्पष्ट होना चाहिए कि FormMixin और DetailView FormMixin के बीच सूक्ष्म बातचीत की संख्या पहले से ही चीजों को प्रबंधित करने की हमारी क्षमता का परीक्षण कर रही है। यह संभावना नहीं है कि आप इस तरह का वर्ग खुद लिखना चाहेंगे।

इस स्थिति में, केवल post() को post() करना आसान होगा post() विधि, केवल DetailView को केवल सामान्य कार्यक्षमता के रूप में रखते हुए, हालाँकि Form हैंडलिंग कोड लिखने में बहुत अधिक दोहराव शामिल है।

वैकल्पिक रूप से, फार्म को संसाधित करने के लिए एक अलग दृष्टिकोण रखने के लिए उपरोक्त दृष्टिकोण की तुलना में यह अभी भी आसान होगा, जो DetailView बिना चिंताओं के DetailView से अलग उपयोग कर सकता है।

एक वैकल्पिक बेहतर उपाय

यहाँ जो हम वास्तव में करने की कोशिश कर रहे हैं वह एक ही URL से दो अलग-अलग वर्ग आधारित विचारों का उपयोग करना है। तो क्यों नहीं बस? हमारे यहां एक बहुत ही स्पष्ट विभाजन है: GET अनुरोधों को DetailView (संदर्भ डेटा में जोड़े गए Form साथ) मिलना चाहिए, और POST अनुरोधों को Form DetailView मिलना चाहिए। आइए पहले उन विचारों को स्थापित करें।

AuthorDisplay दृश्य लगभग वैसा ही है जब हमने पहली बार ऑथोरटेल को पेश किया था ; हमें अपने स्वयं के get_context_data() को AuthorInterestForm टेम्प्लेट को उपलब्ध कराने के लिए AuthorInterestForm होगा। हम स्पष्टता के लिए पहले से get_object() ओवरराइड छोड़ देंगे:

from django import forms
from django.views.generic import DetailView
from books.models import Author

class AuthorInterestForm(forms.Form):
    message = forms.CharField()

class AuthorDisplay(DetailView):
    model = Author

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = AuthorInterestForm()
        return context

तब AuthorInterest एक साधारण AuthorInterest है, लेकिन हमें SingleObjectMixin में लाना है ताकि हम उस लेखक को पा सकें जिसके बारे में हम बात कर रहे हैं, और हमें यह सुनिश्चित करने के लिए template_name को सेट करना होगा कि यह सुनिश्चित करें कि त्रुटि उसी टेम्पलेट को प्रस्तुत करेगी, जिसके बारे में SingleObjectMixin उपयोग कर रहा है। GET :

from django.http import HttpResponseForbidden
from django.urls import reverse
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin

class AuthorInterest(SingleObjectMixin, FormView):
    template_name = 'books/author_detail.html'
    form_class = AuthorInterestForm
    model = Author

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()
        return super().post(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('author-detail', kwargs={'pk': self.object.pk})

अंत में हम इसे एक नए AuthorDetail दृश्य में एक साथ AuthorDetail हैं। हम पहले से ही जानते हैं कि क्लास-आधारित दृश्य पर as_view() कॉल करने से हमें कुछ ऐसा मिलता है, जो बिल्कुल फ़ंक्शन आधारित दृश्य की तरह व्यवहार करता है, इसलिए हम ऐसा कर सकते हैं कि हम दो as_view() एक का चयन करें।

आप अपने as_view() कीवर्ड तर्क से as_view() में उसी तरह से गुजर सकते हैं, जैसे कि यदि आप चाहते थे कि AuthorInterest व्यवहार किसी अन्य URL पर भी दिखाई दे, लेकिन एक अलग टेम्पलेट का उपयोग कर:

from django.views import View

class AuthorDetail(View):

    def get(self, request, *args, **kwargs):
        view = AuthorDisplay.as_view()
        return view(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        view = AuthorInterest.as_view()
        return view(request, *args, **kwargs)

इस दृष्टिकोण का उपयोग किसी भी अन्य सामान्य वर्ग-आधारित विचारों या अपने स्वयं के वर्ग-आधारित विचारों के साथ किया जा सकता है जो सीधे View या TemplateView View से विरासत में मिलते हैं, क्योंकि यह विभिन्न विचारों को यथासंभव अलग रखता है।

सिर्फ HTML से ज्यादा

जहां क्लास-आधारित विचार चमकते हैं, जब आप एक ही चीज़ को कई बार करना चाहते हैं। मान लीजिए कि आप एक एपीआई लिख रहे हैं, और हर दृश्य को HTML प्रदान करने के बजाय JSON वापस करना चाहिए।

हम एक बार JSON में रूपांतरण को संभालने के लिए, हमारे सभी विचारों में उपयोग करने के लिए एक मिश्रण वर्ग बना सकते हैं।

उदाहरण के लिए, एक साधारण JSON मिक्सिन कुछ इस तरह दिख सकता है:

from django.http import JsonResponse

class JSONResponseMixin:
    """
    A mixin that can be used to render a JSON response.
    """
    def render_to_json_response(self, context, **response_kwargs):
        """
        Returns a JSON response, transforming 'context' to make the payload.
        """
        return JsonResponse(
            self.get_data(context),
            **response_kwargs
        )

    def get_data(self, context):
        """
        Returns an object that will be serialized as JSON by json.dumps().
        """
        # Note: This is *EXTREMELY* naive; in reality, you'll need
        # to do much more complex handling to ensure that arbitrary
        # objects -- such as Django model instances or querysets
        # -- can be serialized as JSON.
        return context

ध्यान दें

Django मॉडल और क्वेरीसेट को JSON में सही रूप से कैसे परिवर्तित किया जाए, इसके बारे में अधिक जानकारी के लिए Serializing Django ऑब्जेक्ट्स दस्तावेज़ देखें।

यह मिक्सचर render_to_json_response() के समान render_to_response() साथ एक render_to_json_response() विधि प्रदान करता है। इसका उपयोग करने के लिए, हमें उदाहरण के लिए बस इसे TemplateView render_to_response() में मिलाना होगा, और render_to_response() को render_to_json_response() करने के लिए render_to_json_response() करने के लिए ओवरराइड करना होगा render_to_json_response() बजाय render_to_json_response()

from django.views.generic import TemplateView

class JSONView(JSONResponseMixin, TemplateView):
    def render_to_response(self, context, **response_kwargs):
        return self.render_to_json_response(context, **response_kwargs)

समान रूप से हम एक सामान्य विचार के साथ हमारे मिश्रण का उपयोग कर सकते हैं। हम DetailView को JSONResponseMixin साथ मिला कर JSONResponseMixin DetailView का अपना संस्करण बना सकते हैं - (टेम्प्लेट रेंडरिंग व्यवहार से पहले DetailView को मिक्स किया गया है):

from django.views.generic.detail import BaseDetailView

class JSONDetailView(JSONResponseMixin, BaseDetailView):
    def render_to_response(self, context, **response_kwargs):
        return self.render_to_json_response(context, **response_kwargs)

इस दृश्य को किसी अन्य DetailView तरह ही ठीक उसी व्यवहार के साथ तैनात किया जा सकता है - प्रतिक्रिया के प्रारूप को छोड़कर।

यदि आप वास्तव में साहसी होना चाहते हैं, तो आप एक एचटीएमएल और DetailView को वापस करने में सक्षम एक DetailView भी मिला सकते हैं, जो HTTP अनुरोध की कुछ संपत्ति पर निर्भर करता है, जैसे कि क्वेरी तर्क या HTTP हेडर। केवल JSONResponseMixin और एक SingleObjectTemplateResponseMixin दोनों को JSONResponseMixin , और उपयोगकर्ता द्वारा अनुरोधित प्रतिक्रिया के प्रकार के आधार पर उचित रेंडरिंग विधि के लिए JSONResponseMixin SingleObjectTemplateResponseMixin render_to_response() के कार्यान्वयन को ओवरराइड करें:

from django.views.generic.detail import SingleObjectTemplateResponseMixin

class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
    def render_to_response(self, context):
        # Look for a 'format=json' GET argument
        if self.request.GET.get('format') == 'json':
            return self.render_to_json_response(context)
        else:
            return super().render_to_response(context)

जिस तरह से पायथन विधि ओवरलोडिंग का समाधान करता है, उसके कारण कॉल super().render_to_response(context) लिए render_to_response() TemplateResponseMixin कार्यान्वयन को बुलाता है।