Django 2.1 - Introduction to class-based views

वर्ग-आधारित विचारों का परिचय




django

वर्ग-आधारित विचारों का परिचय

क्लास-आधारित विचार कार्यों के बजाय पायथन ऑब्जेक्ट्स के रूप में विचारों को लागू करने का एक वैकल्पिक तरीका प्रदान करते हैं। वे फ़ंक्शन-आधारित विचारों को प्रतिस्थापित नहीं करते हैं, लेकिन फ़ंक्शन-आधारित विचारों की तुलना में कुछ अंतर और फायदे हैं:

  • विशिष्ट HTTP विधियों ( GET , POST , आदि) से संबंधित कोड के संगठन को सशर्त शाखाओं के बजाय अलग-अलग तरीकों से संबोधित किया जा सकता है।
  • मिक्सविंस (मल्टीपल इनहेरिटेंस) जैसी ऑब्जेक्ट ओरिएंटेड तकनीकों का उपयोग पुन: प्रयोज्य घटकों में कारक कोड के लिए किया जा सकता है।

सामान्य विचारों, वर्ग-आधारित विचारों और वर्ग-आधारित सामान्य विचारों का संबंध और इतिहास

शुरुआत में केवल व्यू फंक्शन कॉन्ट्रैक्ट था, Django ने आपके फंक्शन को HttpRequest और एक HttpResponse उम्मीद की। यह Django द्वारा प्रदान की गई हद थी।

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

फ़ंक्शन-आधारित जेनेरिक विचारों के साथ समस्या यह है कि जब वे सरल मामलों को अच्छी तरह से कवर करते हैं, तो कुछ सरल कॉन्फ़िगरेशन विकल्पों से परे उन्हें विस्तारित या अनुकूलित करने का कोई तरीका नहीं था, जो कई वास्तविक दुनिया के अनुप्रयोगों में उनकी उपयोगिता को सीमित करता है।

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

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

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

वर्ग-आधारित विचारों का उपयोग करना

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

तो जहां एक दृश्य समारोह में HTTP GET को संभालने के लिए कोड कुछ इस तरह दिखाई देगा:

from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')

क्लास-आधारित दृश्य में, यह बन जाएगा:

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')

क्योंकि Django का URL रिज़ॉल्वर एक as_view() करने योग्य फ़ंक्शन के लिए अनुरोध और संबंधित तर्क भेजने की अपेक्षा करता है, न कि एक वर्ग, वर्ग-आधारित विचारों में एक as_view() वर्ग विधि होती है जो एक फ़ंक्शन देता है जिसे कॉल किया जा सकता है जब एक URL संबंधित मेल के लिए अनुरोध आता है पैटर्न। फ़ंक्शन वर्ग का एक उदाहरण बनाता है और इसकी dispatch() विधि कहता है। dispatch यह निर्धारित करने के अनुरोध को देखता है कि क्या यह एक GET , POST , इत्यादि है, और एक मिलान विधि के लिए अनुरोध को रिले करता है यदि कोई परिभाषित है, या नहीं तो HttpResponseNotAllowed उठाता है:

# urls.py
from django.urls import path
from myapp.views import MyView

urlpatterns = [
    path('about/', MyView.as_view()),
]

यह ध्यान देने योग्य है कि आपकी विधि रिटर्न क्या है जो आप फ़ंक्शन-आधारित दृश्य से लौटते हैं, अर्थात HttpResponse का कुछ रूप। इसका मतलब है कि http- शॉर्टकट या TemplateResponse ऑब्जेक्ट्स क्लास-आधारित दृश्य के अंदर उपयोग करने के लिए मान्य हैं।

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

पहला उपवर्ग में सब-क्लासिंग और ओवरराइडिंग विशेषताओं और विधियों का मानक पायथन तरीका है। ताकि अगर आपके अभिभावक वर्ग को इस तरह का greeting पड़े:

from django.http import HttpResponse
from django.views import View

class GreetingView(View):
    greeting = "Good Day"

    def get(self, request):
        return HttpResponse(self.greeting)

आप एक उपवर्ग में इसे ओवरराइड कर सकते हैं:

class MorningGreetingView(GreetingView):
    greeting = "Morning to ya"

एक अन्य विकल्प as_view() तर्कों के रूप में वर्ग विशेषताओं को as_view() में as_view() कॉल में कॉन्फ़िगर करना है:

urlpatterns = [
    path('about/', GreetingView.as_view(greeting="G'day")),
]

ध्यान दें

जब आपकी कक्षा को भेजे गए प्रत्येक अनुरोध के लिए as_view() किया जाता है, तो as_view() प्रविष्टि बिंदु के माध्यम से सेट की गई वर्ग विशेषताएँ केवल उस समय कॉन्फ़िगर की जाती हैं जब आपके URL आयात किए जाते हैं।

मिश्रण का उपयोग करना

मिक्सिन कई वंशानुक्रम का एक रूप है जहां कई माता-पिता वर्गों के व्यवहार और विशेषताओं को जोड़ा जा सकता है।

उदाहरण के लिए, सामान्य वर्ग-आधारित विचारों में TemplateResponseMixin नामक एक मिक्सिन होता है जिसका प्राथमिक उद्देश्य render_to_response() विधि को परिभाषित करना है। जब View बेस क्लास के व्यवहार के साथ जोड़ दिया जाता है, तो परिणाम एक TemplateView View क्लास होता है जो उपयुक्त मिलान विधियों ( View बेस क्लास में परिभाषित एक व्यवहार) के लिए अनुरोध render_to_response() , और जिसमें एक render_to_response() विधि है जो एक template_name विशेषता का उपयोग करता है TemplateResponse ऑब्जेक्ट ( TemplateResponseMixin में परिभाषित एक व्यवहार) को वापस करने के लिए।

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

यह भी ध्यान दें कि आप केवल एक सामान्य दृश्य से उत्तराधिकार प्राप्त कर सकते हैं - अर्थात्, केवल एक मूल वर्ग View से विरासत में मिल सकता है और बाकी (यदि कोई हो) मिक्सिन्स होना चाहिए। View से विरासत में मिली एक से अधिक कक्षाओं से विरासत की कोशिश करना - उदाहरण के लिए, किसी सूची के शीर्ष पर एक फॉर्म का उपयोग करने की कोशिश करना और ProcessFormView और ListView संयोजन - अपेक्षा के अनुरूप काम नहीं करेगा।

क्लास-आधारित विचारों के साथ हैंडलिंग फ़ॉर्म

एक मूल फ़ंक्शन-आधारित दृश्य जो प्रपत्रों को संभालता है, कुछ इस तरह दिख सकता है:

from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import MyForm

def myview(request):
    if request.method == "POST":
        form = MyForm(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')
    else:
        form = MyForm(initial={'key': 'value'})

    return render(request, 'form_template.html', {'form': form})

एक समान श्रेणी-आधारित दृश्य जैसा दिख सकता है:

from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View

from .forms import MyForm

class MyFormView(View):
    form_class = MyForm
    initial = {'key': 'value'}
    template_name = 'form_template.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')

        return render(request, self.template_name, {'form': form})

यह एक बहुत ही सरल मामला है, लेकिन आप देख सकते हैं कि तब आपके पास किसी भी वर्ग विशेषताओं, जैसे कि form_class , URLconf कॉन्फ़िगरेशन के माध्यम से, या सबक्लासिंग और एक या अधिक विधियों (या दोनों) को ओवरराइड करके इस दृश्य को अनुकूलित करने का विकल्प होगा। !)।

सजा वर्ग-आधारित विचार

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

URLconf में सजा

क्लास-आधारित विचारों को सजाने का सबसे सरल तरीका है as_view() विधि के परिणाम को सजाने के लिए। ऐसा करने के लिए सबसे आसान स्थान URLconf में है जहाँ आप अपना दृष्टिकोण तैनात करते हैं:

from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = [
    path('about/', login_required(TemplateView.as_view(template_name="secret.html"))),
    path('vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]

यह दृष्टिकोण डेकोर को प्रति-आवृत्ति के आधार पर लागू करता है। यदि आप चाहते हैं कि हर दृश्य को सजाया जाए, तो आपको एक अलग दृष्टिकोण अपनाने की आवश्यकता है।

कक्षा की सजावट करना

कक्षा-आधारित दृश्य के प्रत्येक उदाहरण को सजाने के लिए, आपको कक्षा की परिभाषा को स्वयं सजाने की आवश्यकता है। ऐसा करने के लिए आप डेकोरेटर को कक्षा के dispatch() पद्धति पर लागू करते हैं।

एक वर्ग पर एक विधि एक स्टैंडअलोन फ़ंक्शन के समान नहीं है, इसलिए आप केवल फ़ंक्शन डेकोरेटर को विधि पर लागू नहीं कर सकते हैं - आपको इसे पहले विधि डेकोरेटर में बदलने की आवश्यकता है। method_decorator डेकोरेटर एक फ़ंक्शन डेकोरेटर को method_decorator डेकोरेटर में बदल देता है ताकि इसे एक इंस्टेंस मेथड पर इस्तेमाल किया जा सके। उदाहरण के लिए:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

या, अधिक संक्षेप में, आप इसके बजाय कक्षा को सजा सकते हैं और कीवर्ड तर्क name रूप में सजाने के लिए विधि का नाम पास कर सकते हैं:

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

यदि आपके पास कई स्थानों पर उपयोग किए जाने वाले सामान्य डेकोरेटर का एक सेट है, तो आप डेकोरेटर की एक सूची या टपल को परिभाषित कर सकते हैं और इसे कई बार method_decorator() को लागू करने के बजाय उपयोग कर सकते हैं। ये दो वर्ग समतुल्य हैं:

decorators = [never_cache, login_required]

@method_decorator(decorators, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

@method_decorator(never_cache, name='dispatch')
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

डेकोरेटर उस क्रम में अनुरोध करेंगे जिस क्रम में वे डेकोरेटर को पास किए जाते हैं। उदाहरण में, never_cache() login_required() से पहले अनुरोध को संसाधित करेगा।

इस उदाहरण में, ProtectedView प्रत्येक उदाहरण में लॉगिन सुरक्षा होगी।

ध्यान दें

method_decorator कक्षा पर सजाए गए विधि के पैरामीटर के रूप में *args और **kwargs करता है। यदि आपकी विधि मापदंडों के संगत सेट को स्वीकार नहीं करती है तो यह TypeError अपवाद को बढ़ा देगा।