Django 2.1

Formsets




django

Formsets

class BaseFormSet [source]

एक फ़ॉर्मेट एक पृष्ठ पर कई रूपों के साथ काम करने के लिए अमूर्तता की एक परत है। यह डेटा ग्रिड की तुलना में सबसे अच्छा हो सकता है। मान लें कि आपके पास निम्नलिखित फ़ॉर्म हैं:

>>> from django import forms
>>> class ArticleForm(forms.Form):
...     title = forms.CharField()
...     pub_date = forms.DateField()

आप उपयोगकर्ता को एक साथ कई लेख बनाने की अनुमति देना चाह सकते हैं। एक ArticleForm से बाहर एक फॉर्मेट बनाने के लिए आप क्या करेंगे:

>>> from django.forms import formset_factory
>>> ArticleFormSet = formset_factory(ArticleForm)

अब आपने ArticleFormSet नाम का एक फॉर्मेट बनाया है। फ़ॉर्मेट आपको फ़ॉर्मेट में प्रपत्रों पर पुनरावृति करने और उन्हें प्रदर्शित करने की क्षमता देता है, जैसा कि आप नियमित रूप से करते हैं:

>>> formset = ArticleFormSet()
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></td></tr>

जैसा कि आप देख सकते हैं कि यह केवल एक खाली रूप प्रदर्शित करता है। प्रदर्शित किए जाने वाले खाली रूपों की संख्या को extra पैरामीटर द्वारा नियंत्रित किया जाता है। डिफ़ॉल्ट रूप से, formset_factory() एक अतिरिक्त रूप को परिभाषित करता है; निम्नलिखित उदाहरण दो रिक्त रूपों को प्रदर्शित करेगा:

>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)

फ़ार्मेट पर formset वे बनाए गए क्रम में प्रपत्र रेंडर करेंगे। आप इस आदेश को __iter__() विधि के लिए एक वैकल्पिक कार्यान्वयन प्रदान करके बदल सकते हैं।

फॉर्मसेट को भी अनुक्रमित किया जा सकता है, जो संबंधित फॉर्म लौटाता है। यदि आप __iter__ ओवरराइड __iter__ , तो आपको मैचिंग व्यवहार करने के लिए __getitem__ को भी ओवरराइड करना होगा।

एक फॉर्मेट के साथ प्रारंभिक डेटा का उपयोग करना

प्रारंभिक डेटा वह है जो किसी फॉर्मेट की मुख्य उपयोगिता को चलाता है। जैसा कि ऊपर दिखाया गया है आप अतिरिक्त रूपों की संख्या को परिभाषित कर सकते हैं। इसका मतलब यह है कि आप फॉर्मेट को बता रहे हैं कि प्रारंभिक डेटा से उत्पन्न होने वाले फॉर्म के अलावा कितने अतिरिक्त फॉर्म दिखाने हैं। आइए एक उदाहरण देखें:

>>> import datetime
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
>>> formset = ArticleFormSet(initial=[
...     {'title': 'Django is now open source',
...      'pub_date': datetime.date.today(),}
... ])

>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date"></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title"></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date"></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title"></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date"></td></tr>

अब कुल तीन फॉर्म दिखाई दे रहे हैं। प्रारंभिक डेटा के लिए एक जिसे दो अतिरिक्त रूपों में पारित किया गया था। यह भी ध्यान दें कि हम प्रारंभिक डेटा के रूप में शब्दकोशों की सूची में पास कर रहे हैं।

यदि आप किसी फॉर्मेट को प्रदर्शित करने के लिए initial उपयोग करते हैं, तो आपको उस फॉर्मेट को सबमिट करते समय उसी initial को पास करना चाहिए, ताकि फॉर्मेट यह पता लगा सके कि उपयोगकर्ता द्वारा कौन से फॉर्म बदले गए हैं। उदाहरण के लिए, आपके पास कुछ ऐसा हो सकता है: ArticleFormSet(request.POST, initial=[...])

रूपों की अधिकतम संख्या को सीमित करना

formset_factory() लिए max_num पैरामीटर आपको formset_factory() प्रदर्शित करने वाले रूपों की संख्या को सीमित करने की क्षमता देता है:

>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
>>> formset = ArticleFormSet()
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></td></tr>

यदि शुरुआती डेटा में max_num की max_num मौजूदा आइटम्स की संख्या से अधिक है, तो extra अतिरिक्त ब्लैंक फॉर्म को max_num जोड़ा जाएगा, इसलिए जब तक कि फॉर्म की कुल संख्या max_num से max_num न हो max_num । उदाहरण के लिए, यदि extra=2 और max_num=2 extra=2 और max_num=2 को एक initial आइटम के साथ आरंभीकृत किया गया है, तो प्रारंभिक आइटम के लिए एक फॉर्म और एक रिक्त फॉर्म प्रदर्शित किया जाएगा।

यदि प्रारंभिक डेटा में आइटमों की संख्या max_num से अधिक है, तो सभी आरंभिक डेटा फ़ॉर्म max_num के मान की परवाह किए बिना प्रदर्शित किए max_num और कोई अतिरिक्त फ़ॉर्म प्रदर्शित नहीं किए जाएंगे। उदाहरण के लिए, यदि extra=3 और max_num=1 और max_num=1 को दो प्रारंभिक वस्तुओं के साथ आरंभ किया गया है, तो प्रारंभिक डेटा वाले दो रूपों को प्रदर्शित किया जाएगा।

None ( max_num एक max_num मूल्य प्रदर्शित (1000) रूपों की संख्या पर एक उच्च सीमा डालता है। व्यवहार में यह कोई सीमा नहीं के बराबर है।

डिफ़ॉल्ट रूप से, max_num केवल कितने रूपों को प्रदर्शित करता है और सत्यापन को प्रभावित नहीं करता है। यदि validate_max=True को formset_factory() , तो max_num सत्यापन को प्रभावित करेगा। देखें validate_max

फॉर्मेट सत्यापन

एक फॉर्मेट के साथ सत्यापन एक नियमित रूप से लगभग समान है। is_valid में सभी रूपों को मान्य करने के लिए एक सुविधाजनक तरीका प्रदान करने के लिए is_valid पर एक is_valid विधि है:

>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm)
>>> data = {
...     'form-TOTAL_FORMS': '1',
...     'form-INITIAL_FORMS': '0',
...     'form-MAX_NUM_FORMS': '',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
True

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

>>> data = {
...     'form-TOTAL_FORMS': '2',
...     'form-INITIAL_FORMS': '0',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': 'Test',
...     'form-0-pub_date': '1904-06-16',
...     'form-1-title': 'Test',
...     'form-1-pub_date': '', # <-- this date is missing but required
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {'pub_date': ['This field is required.']}]

जैसा कि हम देख सकते हैं, formset.errors एक सूची है जिसकी प्रविष्टियाँ formset.errors में रूपों से मेल खाती हैं। प्रत्येक दो रूपों के लिए सत्यापन किया गया था, और दूसरे आइटम के लिए अपेक्षित त्रुटि संदेश प्रकट होता है।

सामान्य Form का उपयोग करते समय, maxlength के प्रत्येक फ़ील्ड में HTML विशेषताएँ शामिल हो सकती हैं जैसे ब्राउज़र सत्यापन के लिए maxlength । हालाँकि, प्रपत्रों के प्रपत्र फ़ील्ड में required विशेषता शामिल नहीं होगी क्योंकि प्रपत्र जोड़ते और हटाते समय सत्यापन गलत हो सकता है।

BaseFormSet.total_error_count() [source]

यह सुनिश्चित करने के लिए कि total_error_count में कितनी त्रुटियां हैं, हम total_error_count विधि का उपयोग कर सकते हैं:

>>> # Using the previous example
>>> formset.errors
[{}, {'pub_date': ['This field is required.']}]
>>> len(formset.errors)
2
>>> formset.total_error_count()
1

हम यह भी जांच सकते हैं कि क्या फॉर्म डेटा प्रारंभिक डेटा से भिन्न है (यानी फॉर्म बिना किसी डेटा के भेजा गया था):

>>> data = {
...     'form-TOTAL_FORMS': '1',
...     'form-INITIAL_FORMS': '0',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': '',
...     'form-0-pub_date': '',
... }
>>> formset = ArticleFormSet(data)
>>> formset.has_changed()
False

ManagementForm को समझना

आपने अतिरिक्त डेटा ( form-TOTAL_FORMS , form-TOTAL_FORMS form-INITIAL_FORMS और form-TOTAL_FORMS form-MAX_NUM_FORMS ) पर ध्यान दिया होगा जो ऊपर दिए गए फॉर्मेट के डेटा में आवश्यक थे। यह डेटा ManagementForm लिए आवश्यक है। इस फॉर्म का उपयोग फॉर्मेट में निहित फॉर्म के संग्रह को प्रबंधित करने के लिए फॉर्मेट द्वारा किया जाता है। यदि आप यह प्रबंधन डेटा प्रदान नहीं करते हैं, तो एक अपवाद उठाया जाएगा:

>>> data = {
...     'form-0-title': 'Test',
...     'form-0-pub_date': '',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
Traceback (most recent call last):
...
django.forms.utils.ValidationError: ['ManagementForm data is missing or has been tampered with']

इसका उपयोग यह देखने के लिए किया जाता है कि कितने फॉर्म इंस्टेंस प्रदर्शित किए जा रहे हैं। यदि आप जावास्क्रिप्ट के माध्यम से नए फॉर्म जोड़ रहे हैं, तो आपको इस फॉर्म में गिनती फ़ील्ड भी बढ़ाना चाहिए। दूसरी ओर, यदि आप मौजूदा वस्तुओं को हटाने की अनुमति देने के लिए जावास्क्रिप्ट का उपयोग कर रहे हैं, तो आपको यह सुनिश्चित करने की आवश्यकता है कि हटाए जा रहे लोगों को POST डेटा में form-#-DELETE सहित ठीक से हटाने के लिए चिह्नित किया गया है। यह उम्मीद की जाती है कि सभी फॉर्म POST डेटा में मौजूद हैं।

प्रबंधन प्रपत्र स्वयं फॉर्मेट की विशेषता के रूप में उपलब्ध है। किसी टेम्प्लेट में किसी {{ my_formset.management_form }} को प्रस्तुत करते समय, आप {{ my_formset.management_form }} प्रतिपादन करके अपने प्रबंधन के सभी आंकड़ों को शामिल कर सकते हैं (उचित रूप में अपने {{ my_formset.management_form }} के नाम का प्रतिस्थापन)।

total_form_count और initial_form_count

BaseFormSet में कुछ तरीके हैं जो ManagementForm , total_form_count और initial_form_count से निकटता से संबंधित हैं।

total_form_count इस total_form_count में कुल total_form_count लौटाता है। initial_form_count पूर्व-भरे गए फ़ॉर्मेट में प्रपत्रों की संख्या लौटाता है, और यह निर्धारित करने के लिए भी उपयोग किया जाता है कि कितने फ़ॉर्म आवश्यक हैं। आपको शायद इन तरीकों में से किसी को भी ओवरराइड करने की आवश्यकता नहीं होगी, इसलिए कृपया सुनिश्चित करें कि आप ऐसा करने से पहले समझते हैं कि वे क्या करते हैं।

empty_form

BaseFormSet एक अतिरिक्त विशेषता प्रदान करता है empty_form जो जावास्क्रिप्ट के साथ गतिशील रूपों में आसान उपयोग के लिए __prefix__ उपसर्ग के साथ एक प्रपत्र उदाहरण देता है।

कस्टम फॉर्मेट सत्यापन

एक फॉर्मेट में एक Form क्लास पर एक समान विधि होती है। यह वह जगह है जहाँ आप अपने स्वयं के सत्यापन को परिभाषित करते हैं जो फॉर्मेट स्तर पर काम करता है:

>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm

>>> class BaseArticleFormSet(BaseFormSet):
...     def clean(self):
...         """Checks that no two articles have the same title."""
...         if any(self.errors):
...             # Don't bother validating the formset unless each form is valid on its own
...             return
...         titles = []
...         for form in self.forms:
...             title = form.cleaned_data['title']
...             if title in titles:
...                 raise forms.ValidationError("Articles in a set must have distinct titles.")
...             titles.append(title)

>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> data = {
...     'form-TOTAL_FORMS': '2',
...     'form-INITIAL_FORMS': '0',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': 'Test',
...     'form-0-pub_date': '1904-06-16',
...     'form-1-title': 'Test',
...     'form-1-pub_date': '1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
['Articles in a set must have distinct titles.']

Form.clean clean विधि को सभी Form.clean विधियों के बाद कहा जाता है। त्रुटियों को non_form_errors() पर non_form_errors() पद्धति का उपयोग करके पाया जाएगा।

एक फॉर्मेट में रूपों की संख्या को मान्य करना

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

validate_max

यदि validate_max=True को formset_factory() , तो सत्यापन यह भी जाँच करेगा कि डेटा सेट में कितने फॉर्म हैं, जो max_num करने के लिए चिह्नित हैं, अधिकतम या उससे अधिक के बराबर है।

>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, max_num=1, validate_max=True)
>>> data = {
...     'form-TOTAL_FORMS': '2',
...     'form-INITIAL_FORMS': '0',
...     'form-MIN_NUM_FORMS': '',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': 'Test',
...     'form-0-pub_date': '1904-06-16',
...     'form-1-title': 'Test 2',
...     'form-1-pub_date': '1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
['Please submit 1 or fewer forms.']

validate_max=True max_num खिलाफ सख्ती से मान्य होता है, भले ही max_num पार हो गया हो क्योंकि आरंभिक डेटा की मात्रा अत्यधिक थी।

ध्यान दें

max_num बावजूद, यदि डेटा सेट में प्रपत्रों की संख्या max_num 1000 से अधिक हो max_num है, तो वह प्रपत्र मान्य करने में विफल हो जाएगा जैसे कि validate_max सेट किए गए थे, और इसके अलावा केवल max_num के पहले 1000 फ़ॉर्म ही मान्य होंगे। शेष को पूरी तरह से काट दिया जाएगा। यह जाली POST अनुरोधों का उपयोग करके मेमोरी थकावट के हमलों से बचाने के लिए है।

validate_min

यदि validate_min=True को formset_factory() , तो सत्यापन यह भी जाँच करेगा कि डेटा सेट में रूपों की संख्या, मिटाने के लिए चिह्नित किए गए formset_factory() की संख्या, min_num से अधिक या बराबर है।

>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, min_num=3, validate_min=True)
>>> data = {
...     'form-TOTAL_FORMS': '2',
...     'form-INITIAL_FORMS': '0',
...     'form-MIN_NUM_FORMS': '',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': 'Test',
...     'form-0-pub_date': '1904-06-16',
...     'form-1-title': 'Test 2',
...     'form-1-pub_date': '1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
['Please submit 3 or more forms.']

आदेशों और प्रपत्रों को हटाने के साथ व्यवहार करना

formset_factory() दो वैकल्पिक पैरामीटर्स can_order और can_delete को can_delete में फॉर्म के ऑर्डर देने और can_delete से can_delete करने में मदद करता है।

can_order

BaseFormSet.can_order

डिफ़ॉल्ट: False

आप ऑर्डर करने की क्षमता के साथ एक फॉर्मेट बनाते हैं:

>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
>>> formset = ArticleFormSet(initial=[
...     {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date"></td></tr>
<tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="number" name="form-0-ORDER" value="1" id="id_form-0-ORDER"></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title"></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date"></td></tr>
<tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="number" name="form-1-ORDER" value="2" id="id_form-1-ORDER"></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title"></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date"></td></tr>
<tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="number" name="form-2-ORDER" id="id_form-2-ORDER"></td></tr>

यह प्रत्येक फॉर्म में एक अतिरिक्त फ़ील्ड जोड़ता है। इस नए फ़ील्ड का नाम ORDER और यह एक forms.IntegerFieldforms.IntegerField । प्रारंभिक डेटा से आए रूपों के लिए यह स्वचालित रूप से उन्हें एक संख्यात्मक मान असाइन करता है। आइए देखें कि उपयोगकर्ता द्वारा इन मूल्यों को बदलने पर क्या होगा:

>>> data = {
...     'form-TOTAL_FORMS': '3',
...     'form-INITIAL_FORMS': '2',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': 'Article #1',
...     'form-0-pub_date': '2008-05-10',
...     'form-0-ORDER': '2',
...     'form-1-title': 'Article #2',
...     'form-1-pub_date': '2008-05-11',
...     'form-1-ORDER': '1',
...     'form-2-title': 'Article #3',
...     'form-2-pub_date': '2008-05-01',
...     'form-2-ORDER': '0',
... }

>>> formset = ArticleFormSet(data, initial=[
...     {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> formset.is_valid()
True
>>> for form in formset.ordered_forms:
...     print(form.cleaned_data)
{'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': 'Article #3'}
{'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': 'Article #2'}
{'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': 'Article #1'}

can_delete

BaseFormSet.can_delete

डिफ़ॉल्ट: False

डिलीट के लिए फॉर्म चुनने की क्षमता के साथ आप एक फॉर्मेट बनाते हैं:

>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
>>> formset = ArticleFormSet(initial=[
...     {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date"></td></tr>
<tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE"></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title"></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date"></td></tr>
<tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE"></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title"></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date"></td></tr>
<tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE"></td></tr>

can_order तरह can_order यह DELETE नाम के प्रत्येक फॉर्म में एक नया फ़ील्ड जोड़ता है और एक forms.BooleanFieldforms.BooleanField । जब डेटा किसी भी हटाए गए फ़ील्ड को चिह्नित करने के माध्यम से आता है, तो आप उन्हें deleted_forms एक्सेस कर सकते हैं:

>>> data = {
...     'form-TOTAL_FORMS': '3',
...     'form-INITIAL_FORMS': '2',
...     'form-MAX_NUM_FORMS': '',
...     'form-0-title': 'Article #1',
...     'form-0-pub_date': '2008-05-10',
...     'form-0-DELETE': 'on',
...     'form-1-title': 'Article #2',
...     'form-1-pub_date': '2008-05-11',
...     'form-1-DELETE': '',
...     'form-2-title': '',
...     'form-2-pub_date': '',
...     'form-2-DELETE': '',
... }

>>> formset = ArticleFormSet(data, initial=[
...     {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> [form.cleaned_data for form in formset.deleted_forms]
[{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': 'Article #1'}]

यदि आप एक ModelFormSet का उपयोग कर रहे हैं, तो जब आप formset.save() कॉल करते हैं, तो हटाए गए प्रपत्रों के मॉडल उदाहरण हटा दिए जाएंगे।

यदि आप formset.save(commit=False) , तो ऑब्जेक्ट स्वचालित रूप से हटाए नहीं जाएंगे। आपको प्रत्येक formset.deleted_objects पर delete() को कॉल करना होगा। वास्तव में उन्हें डिलीट करने के लिए:

>>> instances = formset.save(commit=False)
>>> for obj in formset.deleted_objects:
...     obj.delete()

दूसरी ओर, यदि आप एक सादे FormSet का उपयोग कर रहे हैं, तो यह आपके ऊपर है कि आप अपने formset.deleted_forms की save() विधि में, शायद formset.deleted_forms को संभाल formset.deleted_forms , क्योंकि किसी फॉर्म को डिलीट करने का कोई सामान्य अर्थ नहीं है।

एक फॉर्मेट में अतिरिक्त फ़ील्ड जोड़ना

यदि आपको फॉर्मेट में अतिरिक्त फ़ील्ड जोड़ने की आवश्यकता है तो इसे आसानी से पूरा किया जा सकता है। फॉर्मसेट बेस क्लास एक add_fields विधि प्रदान करता है। आप अपने स्वयं के फ़ील्ड को जोड़ने के लिए इस विधि को ओवरराइड कर सकते हैं या यहां तक ​​कि डिफ़ॉल्ट फ़ील्ड / ऑर्डर और विलोपन फ़ील्ड की विशेषताओं को फिर से परिभाषित कर सकते हैं:

>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
...     def add_fields(self, form, index):
...         super().add_fields(form, index)
...         form.fields["my_field"] = forms.CharField()

>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> formset = ArticleFormSet()
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></td></tr>
<tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field"></td></tr>

फॉरमेट के लिए कस्टम पैरामीटर पास करना

कभी-कभी आपका फॉर्म क्लास कस्टम पैरामीटर लेता है, जैसे MyArticleForm । आप इस पैरामीटर को तब पास कर सकते हैं जब फॉर्मेट को तत्काल किया जा रहा हो:

>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm

>>> class MyArticleForm(ArticleForm):
...     def __init__(self, *args, user, **kwargs):
...         self.user = user
...         super().__init__(*args, **kwargs)

>>> ArticleFormSet = formset_factory(MyArticleForm)
>>> formset = ArticleFormSet(form_kwargs={'user': request.user})

form_kwargs विशिष्ट प्रपत्र उदाहरण पर भी निर्भर हो सकता है। get_form_kwargs बेस क्लास एक get_form_kwargs विधि प्रदान करता है। विधि एकल तर्क लेती है - फॉर्मेट में फॉर्म का सूचकांक। अनुक्रमणिका empty_form लिए None :

>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory

>>> class BaseArticleFormSet(BaseFormSet):
...     def get_form_kwargs(self, index):
...         kwargs = super().get_form_kwargs(index)
...         kwargs['custom_kwarg'] = index
...         return kwargs

एक फॉर्मेट के उपसर्ग को अनुकूलित करना

प्रदान किए गए HTML में, फ़ॉर्मेट्स में प्रत्येक फ़ील्ड के नाम पर एक उपसर्ग शामिल होता है। डिफ़ॉल्ट रूप से, उपसर्ग 'form' , लेकिन इसे फॉर्मेट के prefix तर्क का उपयोग करके अनुकूलित किया जा सकता है।

उदाहरण के लिए, डिफ़ॉल्ट मामले में, आप देख सकते हैं:

<label for="id_form-0-title">Title:</label>
<input type="text" name="form-0-title" id="id_form-0-title">

लेकिन ArticleFormset(prefix='article') जो बन जाता है:

<label for="id_article-0-title">Title:</label>
<input type="text" name="article-0-title" id="id_article-0-title">

यदि आप एक दृश्य में एक से अधिक फॉर्मेट का उपयोग करना चाहते हैं तो यह उपयोगी है।

विचारों और टेम्पलेट्स में एक फॉर्मेट का उपयोग करना

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

from django.forms import formset_factory
from django.shortcuts import render
from myapp.forms import ArticleForm

def manage_articles(request):
    ArticleFormSet = formset_factory(ArticleForm)
    if request.method == 'POST':
        formset = ArticleFormSet(request.POST, request.FILES)
        if formset.is_valid():
            # do something with the formset.cleaned_data
            pass
    else:
        formset = ArticleFormSet()
    return render(request, 'manage_articles.html', {'formset': formset})

manage_articles.html टेम्पलेट इस तरह दिख सकता है:

<form method="post">
    {{ formset.management_form }}
    <table>
        {% for form in formset %}
        {{ form }}
        {% endfor %}
    </table>
</form>

हालाँकि, फॉर्मेट को प्रबंधन फ़ॉर्म से निपटने की अनुमति देकर ऊपर के लिए एक छोटा शॉर्टकट है:

<form method="post">
    <table>
        {{ formset }}
    </table>
</form>

ऊपर के as_table क्लास पर as_table मेथड कहते हुए समाप्त होता है।

मैन्युअल रूप से प्रदान किया गया can_delete और can_order

यदि आप मैन्युअल रूप से टेम्प्लेट में फ़ील्ड रेंडर करते हैं, तो आप {{ form.DELETE }} साथ can_delete पैरामीटर रेंडर कर सकते हैं:

<form method="post">
    {{ formset.management_form }}
    {% for form in formset %}
        <ul>
            <li>{{ form.title }}</li>
            <li>{{ form.pub_date }}</li>
            {% if formset.can_delete %}
                <li>{{ form.DELETE }}</li>
            {% endif %}
        </ul>
    {% endfor %}
</form>

इसी तरह, यदि can_order=True ऑर्डर करने की क्षमता है ( can_order=True ), तो इसे {{ form.ORDER }} साथ रेंडर करना संभव है।

एक दृश्य में एक से अधिक फॉर्मेट का उपयोग करना

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

from django.forms import formset_factory
from django.shortcuts import render
from myapp.forms import ArticleForm, BookForm

def manage_articles(request):
    ArticleFormSet = formset_factory(ArticleForm)
    BookFormSet = formset_factory(BookForm)
    if request.method == 'POST':
        article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
        book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
        if article_formset.is_valid() and book_formset.is_valid():
            # do something with the cleaned_data on the formsets.
            pass
    else:
        article_formset = ArticleFormSet(prefix='articles')
        book_formset = BookFormSet(prefix='books')
    return render(request, 'manage_articles.html', {
        'article_formset': article_formset,
        'book_formset': book_formset,
    })

फिर आप सामान्य रूप से फॉर्मेट्स को प्रस्तुत करेंगे। यह इंगित करना महत्वपूर्ण है कि आपको POST और गैर-POST दोनों मामलों में prefix पास करने की आवश्यकता है ताकि यह सही तरीके से प्रस्तुत और संसाधित हो।

प्रत्येक फॉर्मेट का prefix डिफ़ॉल्ट form prefix को प्रतिस्थापित करता है जो प्रत्येक फ़ील्ड के name और id HTML विशेषताओं में जोड़ा जाता है।