Django 2.1 - Writing your first Django app, part 4

अपना पहला Django ऐप लिखना, भाग 4




django

अपना पहला Django ऐप लिखना, भाग 4

यह ट्यूटोरियल शुरू होता है जहां ट्यूटोरियल 3 ने छोड़ दिया। हम वेब-पोल एप्लिकेशन को जारी रख रहे हैं और सरल फॉर्म प्रसंस्करण और हमारे कोड को काटने पर ध्यान केंद्रित करेंगे।

एक सरल रूप लिखें

चलिए अंतिम ट्यूटोरियल से हमारे पोल डिटेल टेम्पलेट ("पोल / डिटेल.html") को अपडेट करते हैं, ताकि टेम्प्लेट में HTML <form> तत्व शामिल हो:

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

एक त्वरित ठहरनेवाला:

  • प्रत्येक प्रश्न के विकल्प के लिए उपरोक्त टेम्पलेट एक रेडियो बटन प्रदर्शित करता है। प्रत्येक रेडियो बटन का value संबद्ध प्रश्न विकल्प आईडी है। प्रत्येक रेडियो बटन का name "choice" । इसका मतलब है, जब कोई व्यक्ति किसी एक रेडियो बटन का चयन करता है और फॉर्म सबमिट करता है, तो वह POST डेटा choice=# जहां # चयनित विकल्प की आईडी है भेज देगा। यह HTML रूपों की मूल अवधारणा है।
  • हम फॉर्म की action को {% url 'polls:vote' question.id %} सेट करते हैं, और हम method="post" सेट करते हैं। method="post" ( method="get" विपरीत method="get" ) का उपयोग करना बहुत महत्वपूर्ण है, क्योंकि इस फॉर्म को जमा करने का कार्य डेटा सर्वर-साइड को बदल देगा। जब भी आप एक फॉर्म बनाते हैं जो डेटा सर्वर-साइड को बदल देता है, तो method="post" उपयोग करें। यह टिप Django के लिए विशिष्ट नहीं है; यह सिर्फ अच्छा वेब विकास अभ्यास है।
  • forloop.counter इंगित करता है कि टैग कितनी बार अपने लूप से forloop.counter है
  • चूंकि हम एक POST फॉर्म बना रहे हैं (जिसमें डेटा को संशोधित करने का प्रभाव हो सकता है), हमें क्रॉस साइट रिक्वेस्ट फोर्सेज के बारे में चिंता करने की आवश्यकता है। शुक्र है, आपको बहुत मुश्किल होने की ज़रूरत नहीं है, क्योंकि Django इसके खिलाफ सुरक्षा के लिए एक बहुत ही आसान उपयोग प्रणाली के साथ आता है। संक्षेप में, आंतरिक URL पर लक्षित सभी POST रूपों को {% csrf_token %} टेम्पलेट टैग का उपयोग करना चाहिए।

अब, एक Django दृश्य बनाते हैं जो सबमिट किए गए डेटा को संभालता है और इसके साथ कुछ करता है। याद रखें, ट्यूटोरियल 3 में , हमने पोल लाइन एप्लिकेशन के लिए एक URLconf बनाया है जिसमें यह लाइन शामिल है:

path('<int:question_id>/vote/', views.vote, name='vote'),

हमने vote() फ़ंक्शन का एक डमी कार्यान्वयन भी बनाया। चलो एक वास्तविक संस्करण बनाते हैं। polls/views.py में निम्नलिखित जोड़ें polls/views.py :

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question
# ...
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

इस कोड में कुछ चीजें शामिल हैं जिन्हें हमने अभी तक इस ट्यूटोरियल में शामिल नहीं किया है:

  • request.POST एक शब्दकोश जैसी वस्तु है, जो आपको मुख्य नाम से प्रस्तुत डेटा तक पहुंचने देती है। इस मामले में, request.POST['choice'] एक स्ट्रिंग के रूप में, चयनित विकल्प की आईडी लौटाता है। request.POST मान हमेशा स्ट्रिंग होते हैं।

    ध्यान दें कि Django भी request.GET प्रदान करता है। उसी तरह से GET डेटा तक पहुंचने के लिए GET - लेकिन हम स्पष्ट रूप से हमारे कोड में request.POST का उपयोग कर रहे हैं, यह सुनिश्चित करने के लिए कि डेटा केवल POST कॉल के माध्यम से बदल दिया गया है।

  • request.POST['choice'] KeyError को बढ़ाएगा यदि POST डेटा में choice प्रदान नहीं किया गया था। यदि कोई choice नहीं दिया गया है, तो KeyError कोड के लिए उपरोक्त कोड की जांच करता है और एक त्रुटि संदेश के साथ प्रश्न को फिर से KeyError
  • पसंद की गिनती बढ़ाने के बाद, कोड एक सामान्य HttpResponse बजाय HttpResponseRedirect लौटाता है। HttpResponseRedirect एक तर्क लेता है: वह URL जिससे उपयोगकर्ता पुनर्निर्देशित किया जाएगा (इस मामले में हम URL का निर्माण कैसे करते हैं इसके लिए निम्न बिंदु देखें)।

    जैसा कि पायथन टिप्पणी ऊपर इंगित करता है, आपको हमेशा POST डेटा से सफलतापूर्वक निपटने के बाद एक HttpResponseRedirect वापस करना चाहिए। यह टिप Django के लिए विशिष्ट नहीं है; यह सिर्फ अच्छा वेब विकास अभ्यास है।

  • हम इस उदाहरण में HttpResponseRedirect निर्माता में reverse() फ़ंक्शन का उपयोग कर रहे हैं। यह फ़ंक्शन व्यू फ़ंक्शन में URL को हार्डकोड करने से बचने में मदद करता है। इसे उस दृश्य का नाम दिया गया है जिसे हम उस पैटर्न की ओर इंगित करने वाले URL पैटर्न के नियंत्रण और चर भाग में भेजना चाहते हैं। इस स्थिति में, हम ट्यूटोरियल 3 में स्थापित URLconf का उपयोग करते हुए, इस reverse() कॉल की तरह एक स्ट्रिंग लौटाएंगे

    '/polls/3/results/'
    

    जहां 3 question.id का मान है। यह पुनर्निर्देशित URL तब अंतिम पृष्ठ प्रदर्शित करने के लिए 'results' दृश्य को कॉल करेगा।

जैसा कि ट्यूटोरियल 3 में बताया गया है, request एक HttpRequest ऑब्जेक्ट है। HttpRequest ऑब्जेक्ट पर अधिक के लिए, अनुरोध और प्रतिक्रिया प्रलेखन देखें

किसी प्रश्न में वोट देने के बाद, vote() प्रश्न के परिणाम पृष्ठ पर पुनर्निर्देश करता है। आइये लिखते हैं वो नज़ारा:

from django.shortcuts import get_object_or_404, render


def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})

यह लगभग ट्यूटोरियल 3 से detail() दृश्य के समान है। केवल अंतर टेम्पलेट नाम है। हम बाद में इस अतिरेक को ठीक कर देंगे।

अब, polls/results.html टेम्पलेट बनाएँ:

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

अब, अपने ब्राउज़र में /polls/1/ पर जाएं और प्रश्न में वोट करें। आपको हर बार मतदान करते समय एक परिणाम पृष्ठ देखना चाहिए जो अपडेट किया जाता है। यदि आप एक विकल्प चुने बिना फॉर्म जमा करते हैं, तो आपको त्रुटि संदेश देखना चाहिए।

ध्यान दें

हमारे vote() के लिए कोड vote() देखने में एक छोटी सी समस्या है। यह पहले डेटाबेस से चयनित_चॉइस ऑब्जेक्ट को प्राप्त करता है, फिर votes के नए मूल्य की गणना करता है, और फिर इसे डेटाबेस में वापस भेजता है। यदि आपकी वेबसाइट के दो उपयोगकर्ता एक ही समय में वोट करने का प्रयास करते हैं, तो यह गलत हो सकता है: एक ही मूल्य, मान लें कि 42, votes लिए पुनर्प्राप्त किए जाएंगे। फिर, दोनों उपयोगकर्ताओं के लिए 43 का नया मान गणना और सहेजा गया है, लेकिन 44 अपेक्षित मूल्य होगा।

इसे रेस कंडीशन कहा जाता है। यदि आप रुचि रखते हैं, तो आप यह जानने के लिए कि आप इस मुद्दे को कैसे हल कर सकते हैं, एफ () का उपयोग करके दौड़ की स्थिति से बच सकते हैं।

सामान्य विचारों का उपयोग करें: कम कोड बेहतर है

detail() ( ट्यूटोरियल 3 से ) और results() दृश्य बहुत सरल हैं - और, जैसा कि ऊपर बताया गया है, निरर्थक। index() दृश्य, जो चुनावों की सूची प्रदर्शित करता है, समान है।

ये विचार बुनियादी वेब विकास के एक सामान्य मामले का प्रतिनिधित्व करते हैं: URL में पारित एक पैरामीटर के अनुसार डेटाबेस से डेटा प्राप्त करना, एक टेम्पलेट लोड करना और प्रदान किए गए टेम्पलेट को वापस करना। क्योंकि यह बहुत आम है, Django एक शॉर्टकट प्रदान करता है, जिसे "सामान्य विचार" प्रणाली कहा जाता है।

जेनेरिक विचारों का सार सामान्य पैटर्न उस बिंदु पर होता है जहाँ आपको ऐप लिखने के लिए पायथन कोड लिखने की भी आवश्यकता नहीं होती है।

आइए जेनेरिक व्यू सिस्टम का उपयोग करने के लिए अपना पोल ऐप बदलें, ताकि हम अपने स्वयं के कोड का एक गुच्छा हटा सकें। रूपांतरण करने के लिए हमें बस कुछ कदम उठाने होंगे। हम करेंगे:

  1. URLconf कन्वर्ट करें।
  2. कुछ पुराने, अनावश्यक विचार हटाएं।
  3. Django के सामान्य विचारों के आधार पर नए विचारों का परिचय दें।

जानकारी के लिए आगे पढ़ें।

कोड-फेरबदल क्यों?

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

कैलकुलेटर का उपयोग शुरू करने से पहले आपको बुनियादी गणित पता होना चाहिए।

URLconf में संशोधन करें

सबसे पहले, polls/urls.py URLconf खोलें और इसे इस तरह बदलें:

from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

ध्यान दें कि दूसरे और तीसरे पैटर्न के पथ तारों में मिलान किए गए पैटर्न का नाम <question_id> से <pk> में बदल गया है।

विचारों में संशोधन करें

इसके बाद, हम अपने पुराने index , detail और results व्यू को हटाने जा रहे हैं और इसके बजाय Django के जेनेरिक व्यू का इस्तेमाल कर रहे हैं। ऐसा करने के लिए, polls/views.py फ़ाइल खोलें और इसे इस तरह बदलें:

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from .models import Choice, Question


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'


class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'


def vote(request, question_id):
    ... # same as above, no changes needed.

हम यहां दो सामान्य विचारों का उपयोग कर रहे हैं: ListView और DetailView । क्रमशः, वे दो विचार "वस्तुओं की एक सूची प्रदर्शित" और "एक विशेष प्रकार की वस्तु के लिए एक विस्तृत पृष्ठ प्रदर्शित करते हैं" की अवधारणाओं को सार करते हैं।

  • प्रत्येक सामान्य दृश्य को यह जानना होगा कि यह किस मॉडल पर कार्य करेगा। यह model विशेषता का उपयोग करके प्रदान किया जाता है।
  • DetailView जेनेरिक दृश्य URL से "pk" कहे जाने वाले प्राथमिक मुख्य मान की अपेक्षा करता है, इसलिए हमने जेनेरिक विचारों question_id लिए pk को pk बदल दिया है।

डिफ़ॉल्ट रूप से, DetailView जेनेरिक दृश्य <app name>/<model name>_detail.html नामक टेम्पलेट का उपयोग करता है। हमारे मामले में, यह "polls/question_detail.html" टेम्पलेट का उपयोग करेगा। template_name विशेषता का उपयोग Django को ऑटोजेनरेटेड डिफ़ॉल्ट टेम्पलेट नाम के बजाय एक विशिष्ट टेम्पलेट नाम का उपयोग करने के लिए कहा जाता है। हम results सूची दृश्य के लिए template_name भी निर्दिष्ट करते हैं - यह सुनिश्चित करता है कि परिणाम दृश्य और विस्तार दृश्य प्रस्तुत होने पर एक अलग उपस्थिति है, भले ही वे दोनों दृश्यों के पीछे एक DetailView दृश्य हो।

इसी तरह, ListView जेनेरिक दृश्य एक डिफ़ॉल्ट टेम्पलेट का उपयोग करता है जिसे <app name>/<model name>_list.html ; अपने मौजूदा "polls/index.html" टेम्पलेट का उपयोग करने के लिए ListView को बताने के लिए हम template_name का उपयोग करते हैं।

ट्यूटोरियल के पिछले भागों में, टेम्प्लेट को एक संदर्भ के साथ प्रदान किया गया है जिसमें question और latest_question_list संदर्भ चर शामिल हैं। विवरण DetailView लिए question चर स्वचालित रूप से प्रदान किया जाता है - चूंकि हम एक Django मॉडल ( Question ) का उपयोग कर रहे हैं, Django संदर्भ चर के लिए एक उपयुक्त नाम निर्धारित करने में सक्षम है। हालाँकि, ListView के लिए, स्वचालित रूप से उत्पन्न संदर्भ चर question_list । इसे ओवरराइड करने के लिए हम latest_question_list विशेषता प्रदान करते हैं, यह निर्दिष्ट करते हुए कि हम इसके बजाय latest_question_list का उपयोग करना चाहते हैं। वैकल्पिक दृष्टिकोण के रूप में, आप नए डिफ़ॉल्ट संदर्भ चर से मिलान करने के लिए अपने टेम्प्लेट को बदल सकते हैं - लेकिन यह केवल Django को आपके द्वारा इच्छित चर का उपयोग करने के लिए बताना बहुत आसान है।

सर्वर चलाएं, और सामान्य विचारों के आधार पर अपने नए मतदान ऐप का उपयोग करें।

जेनेरिक विचारों पर पूर्ण विवरण के लिए, जेनेरिक विचार प्रलेखन देखें

जब आप फ़ॉर्म और सामान्य विचारों के साथ सहज हों, तो हमारे पोल ऐप का परीक्षण करने के बारे में जानने के लिए इस ट्यूटोरियल के भाग 5 को पढ़ें।