Django 2.1 - Creating forms from models

मॉडल से फॉर्म बनाना




django

मॉडल से फॉर्म बनाना

ModelForm

class ModelForm [source]

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

इस कारण से, Django एक सहायक वर्ग प्रदान करता है जो आपको Django मॉडल से Form क्लास बनाने देता है।

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

>>> from django.forms import ModelForm
>>> from myapp.models import Article

# Create the form class.
>>> class ArticleForm(ModelForm):
...     class Meta:
...         model = Article
...         fields = ['pub_date', 'headline', 'content', 'reporter']

# Creating a form to add an article.
>>> form = ArticleForm()

# Creating a form to change an existing article.
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)

फ़ील्ड प्रकार

फ़ील्ड प्रपत्र में निर्दिष्ट क्रम में प्रत्येक मॉडल फ़ील्ड के लिए जनरेट किए गए Form क्लास में एक फॉर्म फ़ील्ड होगा।

प्रत्येक मॉडल फ़ील्ड में एक समान डिफ़ॉल्ट प्रपत्र फ़ील्ड होता है। उदाहरण के लिए, एक मॉडल पर एक CharField को एक फार्म पर CharField रूप में दर्शाया जाता है। एक मॉडल ManyToManyField को एक ManyToManyField रूप में दर्शाया गया है। यहां रूपांतरणों की पूरी सूची दी गई है:

मॉडल क्षेत्र फॉर्म फील्ड
AutoField रूप में प्रतिनिधित्व नहीं किया
BigAutoField रूप में प्रतिनिधित्व नहीं किया
BigIntegerField IntegerField साथ min_value सेट किया गया और max_value सेट किया गया।
BinaryField CharField , यदि editable मॉडल क्षेत्र पर True पर सेट है, अन्यथा प्रपत्र में प्रतिनिधित्व नहीं किया गया है।
BooleanField BooleanField , या NullBooleanField यदि null=True
CharField मॉडल फ़ील्ड के empty_value और empty_value लिए empty_value सेट के साथ empty_value यदि null=True
DateField DateField
DateTimeField DateTimeField
DecimalField DecimalField
EmailField EmailField
FileField FileField
FilePathField FilePathField
FloatField FloatField
ForeignKey ModelChoiceField (नीचे देखें)
ImageField ImageField
IntegerField IntegerField
IPAddressField IPAddressField
GenericIPAddressField GenericIPAddressField
ManyToManyField ModelMultipleChoiceField (नीचे देखें)
NullBooleanField NullBooleanField
PositiveIntegerField IntegerField
PositiveSmallIntegerField IntegerField
SlugField SlugField
SmallIntegerField IntegerField
TextField widget=forms.Textarea साथ CharField widget=forms.Textarea
TimeField TimeField
URLField URLField

जैसा कि आप उम्मीद कर सकते हैं, ForeignKey और ManyToManyField मॉडल फील्ड प्रकार विशेष मामले हैं:

  • ForeignKey का प्रतिनिधित्व django.forms.ModelChoiceField द्वारा किया django.forms.ModelChoiceField , जो एक ChoiceField जिसकी पसंद एक मॉडल QuerySet
  • django.forms.ModelMultipleChoiceField का प्रतिनिधित्व django.forms.ModelMultipleChoiceField द्वारा किया django.forms.ModelMultipleChoiceField , जो एक MultipleChoiceField जिसकी पसंद एक मॉडल QuerySet

इसके अलावा, प्रत्येक उत्पन्न प्रपत्र फ़ील्ड में निम्नानुसार विशेषताएँ सेट हैं:

  • यदि मॉडल फ़ील्ड में blank=True , तो required है कि प्रपत्र फ़ील्ड पर False पर सेट किया गया है। अन्यथा, required=True
  • प्रपत्र फ़ील्ड का label मॉडल फ़ील्ड के verbose_name पर सेट किया गया है, जिसमें पहले वर्ण को कैपिटल किया गया है।
  • प्रपत्र फ़ील्ड का help_text मॉडल फ़ील्ड के help_text पर सेट किया गया है।
  • यदि मॉडल फ़ील्ड में choices सेट हैं, तो मॉडल फ़ील्ड के choices से आने वाले विकल्पों के साथ फ़ॉर्म फ़ील्ड के widget का Select करने के लिए सेट किया जाएगा। विकल्पों में सामान्य रूप से रिक्त विकल्प शामिल होगा जिसे डिफ़ॉल्ट रूप से चुना गया है। यदि फ़ील्ड आवश्यक है, तो यह उपयोगकर्ता को चयन करने के लिए बाध्य करता है। यदि मॉडल फ़ील्ड में blank=False और एक स्पष्ट default मान है (तो default मान प्रारंभ में इसके बजाय चुना जाएगा) रिक्त विकल्प शामिल नहीं किया जाएगा।

अंत में, ध्यान दें कि आप किसी दिए गए मॉडल फ़ील्ड के लिए उपयोग किए गए फ़ॉर्म फ़ील्ड को ओवरराइड कर सकते हैं। नीचे डिफ़ॉल्ट फ़ील्ड ओवरराइड करना देखें।

एक पूर्ण उदाहरण

मॉडल के इस सेट पर विचार करें:

from django.db import models
from django.forms import ModelForm

TITLE_CHOICES = (
    ('MR', 'Mr.'),
    ('MRS', 'Mrs.'),
    ('MS', 'Ms.'),
)

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3, choices=TITLE_CHOICES)
    birth_date = models.DateField(blank=True, null=True)

    def __str__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ['name', 'title', 'birth_date']

class BookForm(ModelForm):
    class Meta:
        model = Book
        fields = ['name', 'authors']

इन मॉडलों के साथ, ऊपर दिया गया ModelForm उपवर्ग लगभग इसी के बराबर होगा (एकमात्र अंतर जो save() विधि है, जिसे हम एक क्षण में चर्चा करेंगे।)।

from django import forms

class AuthorForm(forms.Form):
    name = forms.CharField(max_length=100)
    title = forms.CharField(
        max_length=3,
        widget=forms.Select(choices=TITLE_CHOICES),
    )
    birth_date = forms.DateField(required=False)

class BookForm(forms.Form):
    name = forms.CharField(max_length=100)
    authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())

एक ModelForm पर मान्यता

एक ModelForm को मान्य करने में दो मुख्य चरण शामिल हैं:

  1. रूप मान्य करना
  2. मॉडल उदाहरण को मान्य करना

सामान्य रूप सत्यापन की तरह, मॉडल फॉर्म सत्यापन को तब ट्रिगर किया जाता है जब is_valid() कॉल is_valid() या errors विशेषता तक पहुंचना और स्पष्ट रूप से full_clean() कॉल करते समय, हालांकि आप आमतौर पर बाद के तरीके का उपयोग नहीं करेंगे।

Model सत्यापन ( Model.full_clean() ) फार्म सत्यापन कदम के भीतर से शुरू हो जाता है, फॉर्म के clean() विधि के बाद कहा जाता है।

चेतावनी

सफाई प्रक्रिया विभिन्न तरीकों से ModelForm कंस्ट्रक्टर को पारित मॉडल उदाहरण को संशोधित करती है। उदाहरण के लिए, मॉडल पर किसी भी दिनांक फ़ील्ड को वास्तविक दिनांक ऑब्जेक्ट में परिवर्तित किया जाता है। असफल सत्यापन एक असंगत स्थिति में अंतर्निहित मॉडल का उदाहरण छोड़ सकता है और इसलिए इसका पुन: उपयोग करने की अनुशंसा नहीं की जाती है।

स्वच्छ () विधि को ओवरराइड करना

आप एक सामान्य फॉर्म पर उसी तरह अतिरिक्त सत्यापन प्रदान करने के लिए मॉडल फॉर्म पर clean() विधि को ओवरराइड कर सकते हैं।

मॉडल ऑब्जेक्ट से जुड़ी एक मॉडल फॉर्म आवृत्ति में एक instance विशेषता होगी जो उस विशिष्ट मॉडल उदाहरण के लिए अपने तरीकों को एक्सेस करती है।

चेतावनी

ModelForm.clean() विधि एक ध्वज सेट करती है जो मॉडल सत्यापन चरण को मॉडल फ़ील्ड की विशिष्टता को मान्य बनाता है जो unique , unique_together या unique रूप से चिह्नित किए जाते हैं।

यदि आप clean() विधि को ओवरराइड करना चाहते हैं और इस सत्यापन को बनाए रखना चाहते हैं, तो आपको पैरेंट क्लास की clean() विधि को कॉल करना होगा।

मॉडल सत्यापन के साथ सहभागिता

सत्यापन प्रक्रिया के भाग के रूप में, ModelForm आपके मॉडल पर प्रत्येक फ़ील्ड की clean() पद्धति को कॉल करेगा, जिसमें आपके प्रपत्र पर संबंधित फ़ील्ड है। यदि आपने किसी मॉडल फ़ील्ड को बाहर कर दिया है, तो उन फ़ील्ड्स पर सत्यापन नहीं चलाया जाएगा। फ़ील्ड की सफाई और सत्यापन कैसे काम करते हैं, इसके बारे में अधिक जानकारी के लिए फ़ॉर्म सत्यापन दस्तावेज़ देखें।

किसी भी विशिष्ट जांच से पहले मॉडल की clean() विधि को बुलाया जाएगा। मॉडल के clean() हुक के बारे में अधिक जानकारी के लिए वस्तुओं का सत्यापन करना देखें।

मॉडल की error_messages संबंध में विचार

form field स्तर या प्रपत्र मेटा स्तर पर परिभाषित त्रुटि संदेश हमेशा model field स्तर पर परिभाषित त्रुटि संदेशों पर वरीयता लेते हैं।

model fields पर परिभाषित त्रुटि संदेश केवल तब उपयोग किए जाते हैं, जब मॉडल सत्यापन चरण के दौरान ValidationError को उठाया जाता है और प्रपत्र स्तर पर कोई भी त्रुटि संदेश परिभाषित नहीं होते हैं।

आप मॉडल के सत्यापन के लिए NON_FIELD_ERRORS से त्रुटि संदेशों को NON_FIELD_ERRORS कुंजी से जोड़कर ModelForm के इनर Meta क्लास के error_messages शब्दकोश में जोड़ सकते हैं:

from django.core.exceptions import NON_FIELD_ERRORS
from django.forms import ModelForm

class ArticleForm(ModelForm):
    class Meta:
        error_messages = {
            NON_FIELD_ERRORS: {
                'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
            }
        }

save() विधि

प्रत्येक ModelForm में एक save() विधि भी है। यह विधि प्रपत्र के लिए बाध्य डेटा से डेटाबेस ऑब्जेक्ट बनाता है और बचाता है। ModelForm का एक उपवर्ग मौजूदा मॉडल उदाहरण को कीवर्ड तर्क instance रूप में स्वीकार कर सकता है; यदि यह आपूर्ति की जाती है, तो save() उस उदाहरण को अपडेट करेगा। यदि इसकी आपूर्ति नहीं की गई है, तो save() निर्दिष्ट मॉडल का एक नया उदाहरण बनाएगा:

>>> from myapp.models import Article
>>> from myapp.forms import ArticleForm

# Create a form instance from POST data.
>>> f = ArticleForm(request.POST)

# Save a new Article object from the form's data.
>>> new_article = f.save()

# Create a form to edit an existing Article, but use
# POST data to populate the form.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(request.POST, instance=a)
>>> f.save()

ध्यान दें कि यदि फॉर्म को मान्य नहीं किया गया है , तो कॉलिंग save() form.errors जांच करके ऐसा करेगा। यदि form.errors डेटा में मान्य नहीं है - अर्थात, यदि form.errors True मूल्यांकन करता है, तो एक ValueError उठाया जाएगा।

यदि कोई वैकल्पिक फ़ील्ड प्रपत्र के डेटा में प्रकट नहीं होता है, तो परिणामी मॉडल आवृत्ति मॉडल फ़ील्ड default का उपयोग करती है, यदि उस फ़ील्ड के लिए एक है। यह व्यवहार उन फ़ील्ड पर लागू नहीं होता है जो CheckboxInput , CheckboxSelectMultiple , या SelectMultiple (या कोई कस्टम विजेट जिसका value_omitted_from_data() विधि हमेशा False चेकबॉक्स से अनचेक हो जाता है और अचयनित <select multiple> एक HTML के डेटा में नहीं दिखाई देते हैं) फार्म जमा करना। यदि आप एक API डिज़ाइन कर रहे हैं, तो कस्टम फ़ॉर्म फ़ील्ड या विजेट का उपयोग करें और इन विजेट्स में से एक का उपयोग करने वाले फ़ील्ड के लिए डिफ़ॉल्ट फ़ॉलबैक व्यवहार चाहते हैं।

यह save() विधि एक वैकल्पिक commit कीवर्ड तर्क को स्वीकार करती है, जो True या False स्वीकार करता है। यदि आप commit=False , तो यह एक ऐसी वस्तु लौटाएगा जो अभी तक डेटाबेस में सेव नहीं हुई है। इस मामले में, यह परिणामी मॉडल उदाहरण पर save() कॉल करने के लिए आप पर निर्भर है। यह उपयोगी है यदि आप इसे सहेजने से पहले ऑब्जेक्ट पर कस्टम प्रसंस्करण करना चाहते हैं, या यदि आप किसी विशेष मॉडल बचत विकल्पों में से किसी एक का उपयोग करना चाहते हैं । डिफ़ॉल्ट रूप से commit True है।

commit=False का उपयोग commit=False का एक और दुष्प्रभाव तब देखा जाता है जब आपके मॉडल का दूसरे मॉडल के साथ कई-से-बहुत संबंध होता है। यदि आपके मॉडल में कई-से-कई संबंध हैं और आप किसी प्रपत्र को सहेजते समय commit=False निर्दिष्ट करते हैं, तो Django तुरंत कई-कई संबंधों के लिए प्रपत्र डेटा को सहेज नहीं सकता है। ऐसा इसलिए है क्योंकि डेटाबेस में उदाहरण मौजूद होने तक उदाहरण के लिए कई-से-कई डेटा को सहेजना संभव नहीं है।

इस समस्या के इर्द-गिर्द काम करने के लिए, हर बार जब आप save_m2m() commit=False का उपयोग करके कोई फॉर्म सेव करते commit=False , तो Django आपके ModelForm उपवर्ग में एक save_m2m() विधि जोड़ता है। प्रपत्र द्वारा उत्पादित उदाहरण को मैन्युअल रूप से सहेजने के बाद, आप कई-से-कई प्रपत्र डेटा सहेजने के लिए save_m2m() को आमंत्रित कर सकते हैं। उदाहरण के लिए:

# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)

# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)

# Modify the author in some way.
>>> new_author.some_field = 'some_value'

# Save the new instance.
>>> new_author.save()

# Now, save the many-to-many data for the form.
>>> f.save_m2m()

save_m2m() कॉल करना केवल तभी आवश्यक है जब आप save(commit=False) । जब आप किसी फॉर्म में एक साधारण save() उपयोग करते हैं, तो सभी डेटा - जिसमें कई-से-कई डेटा शामिल हैं - बिना किसी अतिरिक्त डेटा कॉल की आवश्यकता के सहेजे जाते हैं। उदाहरण के लिए:

# Create a form instance with POST data.
>>> a = Author()
>>> f = AuthorForm(request.POST, instance=a)

# Create and save the new author instance. There's no need to do anything else.
>>> new_author = f.save()

save() और save_m2m() विधियों के अलावा, एक ModelForm ठीक उसी तरह काम करता है जैसे कोई अन्य forms । उदाहरण के लिए, is_valid() विधि का उपयोग वैधता की जांच करने के लिए किया जाता है, is_multipart() विधि का उपयोग यह निर्धारित करने के लिए किया जाता है कि क्या किसी प्रपत्र को मल्टीपार्ट फ़ाइल अपलोड करने की आवश्यकता है (और इसलिए क्या request.FILES को प्रपत्र को पारित किया जाना चाहिए), आदि बाइंडिंग देखें। अधिक जानकारी के लिए प्रपत्र में फ़ाइलें अपलोड की गईं

उपयोग करने के लिए खेतों का चयन करना

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

वैकल्पिक दृष्टिकोण सभी क्षेत्रों को स्वचालित रूप से शामिल करना होगा, या केवल कुछ को ब्लैकलिस्ट करना होगा। इस मूलभूत दृष्टिकोण को बहुत कम सुरक्षित माना जाता है और इसने प्रमुख वेबसाइटों (जैसे GitHub ) पर गंभीर कारनामे किए हैं।

हालाँकि, ऐसे मामलों के लिए दो शॉर्टकट उपलब्ध हैं जहाँ आप गारंटी दे सकते हैं कि ये सुरक्षा चिंताएँ आप पर लागू नहीं होती हैं:

  1. fields मान को विशेष मान '__all__' पर सेट करें ताकि यह इंगित किया जा सके कि मॉडल में सभी फ़ील्ड का उपयोग किया जाना चाहिए। उदाहरण के लिए:

    from django.forms import ModelForm
    
    class AuthorForm(ModelForm):
        class Meta:
            model = Author
            fields = '__all__'
    
  2. फॉर्म से बाहर किए जाने वाले फ़ील्ड की सूची में ModelForm के इनर Meta क्लास के exclude विशेषता को सेट करें।

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

    class PartialAuthorForm(ModelForm):
        class Meta:
            model = Author
            exclude = ['title']
    

    चूँकि Author मॉडल में 3 फ़ील्ड्स का name , title और birth_date , इस वजह से फॉर्म में फ़ील्ड name और birth_date मौजूद रहेंगे।

यदि इनमें से किसी एक का उपयोग किया जाता है, तो फ़ील्ड जिस रूप में प्रकट होता है वह क्रम होगा जिस क्रम को मॉडल में फ़ील्ड परिभाषित किया गया है, जिसमें कई ManyToManyField इंस्टेंसेस अंतिम दिखाई दे रहे हैं।

इसके अलावा, Django निम्नलिखित नियम लागू करता है: यदि आप मॉडल फ़ील्ड पर editable=False सेट करते हैं, तो ModelForm माध्यम से मॉडल से बनाया गया कोई भी फ़ॉर्म उस फ़ील्ड को शामिल नहीं करेगा।

ध्यान दें

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

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

author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()

वैकल्पिक रूप से, आप save(commit=False) सकते हैं save(commit=False) और मैन्युअल रूप से किसी भी अतिरिक्त आवश्यक फ़ील्ड सेट कर सकते हैं:

form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()

save(commit=False) का उपयोग save(commit=False) पर अधिक विवरण के लिए बचत प्रपत्रों पर अनुभाग देखें।

डिफ़ॉल्ट फ़ील्ड को ओवरराइड करना

डिफ़ॉल्ट फ़ील्ड प्रकार, जैसा कि ऊपर दी गई फ़ील्ड प्रकार तालिका में वर्णित है, समझदार चूक हैं। यदि आपके पास अपने मॉडल में एक DateField है, तो संभावना है कि आप चाहते हैं कि आपके फॉर्म में DateField रूप में प्रतिनिधित्व किया DateField । लेकिन ModelForm आपको किसी दिए गए मॉडल के लिए प्रपत्र फ़ील्ड को बदलने की सुविधा देता है।

किसी फ़ील्ड के लिए कस्टम विजेट निर्दिष्ट करने के लिए, आंतरिक Meta क्लास के widgets विशेषता का उपयोग करें। यह विजेट कक्षाओं या उदाहरणों के लिए एक शब्दकोश मानचित्रण फ़ील्ड नाम होना चाहिए।

उदाहरण के लिए, यदि आप चाहते हैं कि Author की name विशेषता के लिए CharField को उसके डिफ़ॉल्ट <input type="text"> बजाय <textarea> द्वारा दर्शाया जाए, तो आप फ़ील्ड के विजेट को ओवरराइड कर सकते हैं:

from django.forms import ModelForm, Textarea
from myapp.models import Author

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        widgets = {
            'name': Textarea(attrs={'cols': 80, 'rows': 20}),
        }

widgets शब्दकोश या तो विजेट उदाहरण (जैसे, Textarea(...) ) या कक्षाओं (जैसे, Textarea ) को स्वीकार करता है।

इसी तरह, यदि आप किसी फ़ील्ड को और कस्टमाइज़ करना चाहते हैं, तो आप आंतरिक Meta क्लास के labels , error_messages और error_messages विशेषताएँ निर्दिष्ट कर सकते हैं।

उदाहरण के लिए यदि आप name फ़ील्ड के लिए स्ट्रिंग का सामना कर रहे सभी उपयोगकर्ता के शब्दों को अनुकूलित करना चाहते हैं:

from django.utils.translation import gettext_lazy as _

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        labels = {
            'name': _('Writer'),
        }
        help_texts = {
            'name': _('Some useful help text.'),
        }
        error_messages = {
            'name': {
                'max_length': _("This writer's name is too long."),
            },
        }

आप फ़ील्ड के प्रकार को फ़ॉर्म द्वारा field_classes से अनुकूलित करने के लिए field_classes भी निर्दिष्ट कर सकते हैं।

उदाहरण के लिए, यदि आप slug क्षेत्र के लिए MySlugFormField का उपयोग करना चाहते हैं, तो आप निम्न कार्य कर सकते हैं:

from django.forms import ModelForm
from myapp.models import Article

class ArticleForm(ModelForm):
    class Meta:
        model = Article
        fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']
        field_classes = {
            'slug': MySlugFormField,
        }

अंत में, यदि आप किसी क्षेत्र पर पूर्ण नियंत्रण चाहते हैं - जिसमें उसके प्रकार, सत्यापनकर्ता, आवश्यक, आदि शामिल हैं - तो आप ऐसा कर सकते हैं जैसे कि आप नियमित रूप से निर्दिष्ट फ़ील्ड में घोषित रूप से निर्दिष्ट कर सकते हैं।

यदि आप किसी क्षेत्र के सत्यापनकर्ता को निर्दिष्ट करना चाहते हैं, तो आप क्षेत्र को घोषित रूप से परिभाषित करके और उसके validators पैरामीटर को निर्धारित करके ऐसा कर सकते हैं:

from django.forms import CharField, ModelForm
from myapp.models import Article

class ArticleForm(ModelForm):
    slug = CharField(validators=[validate_slug])

    class Meta:
        model = Article
        fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']

ध्यान दें

जब आप स्पष्ट रूप से एक फॉर्म फ़ील्ड को इस तरह से त्वरित करते हैं, तो यह समझना महत्वपूर्ण है कि ModelForm और नियमित रूप कैसे संबंधित हैं।

ModelForm एक नियमित Form जो स्वचालित रूप से कुछ क्षेत्रों को उत्पन्न कर सकता है। स्वतः उत्पन्न होने वाले क्षेत्र Meta क्लास की सामग्री पर निर्भर करते हैं और जिन क्षेत्रों को पहले से ही घोषित रूप से परिभाषित किया गया है। असल में, ModelForm केवल उन फ़ील्ड्स को उत्पन्न करेगा जो फॉर्म से गायब हैं, या दूसरे शब्दों में, ऐसे फ़ील्ड जिन्हें घोषित रूप से परिभाषित नहीं किया गया था।

घोषित रूप से परिभाषित फ़ील्ड को इस प्रकार छोड़ दिया जाता है, इसलिए Meta विशेषताओं जैसे widgets , labels , error_messages , या error_messages में किए गए किसी भी अनुकूलन को अनदेखा किया जाता है; ये केवल उन क्षेत्रों पर लागू होते हैं जो स्वचालित रूप से उत्पन्न होते हैं।

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

उदाहरण के लिए, यदि Article मॉडल ऐसा दिखता है:

class Article(models.Model):
    headline = models.CharField(
        max_length=200,
        null=True,
        blank=True,
        help_text='Use puns liberally',
    )
    content = models.TextField()

और आप headline लिए कुछ कस्टम सत्यापन करना चाहते हैं, जबकि blank और help_text मानों को निर्दिष्ट रखते हुए, आप इस तरह ArticleForm को परिभाषित कर सकते हैं:

class ArticleForm(ModelForm):
    headline = MyFormField(
        max_length=200,
        required=False,
        help_text='Use puns liberally',
    )

    class Meta:
        model = Article
        fields = ['headline', 'content']

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

खेतों और उनके तर्कों पर अधिक जानकारी के लिए प्रपत्र फ़ील्ड दस्तावेज़ देखें।

खेतों का स्थानीयकरण सक्षम करना

डिफ़ॉल्ट रूप से, एक ModelForm में फ़ील्ड उनके डेटा को स्थानीय नहीं करेगा। खेतों के लिए स्थानीयकरण को सक्षम करने के लिए, आप Meta क्लास पर localized_fields विशेषता का उपयोग कर सकते हैं।

>>> from django.forms import ModelForm
>>> from myapp.models import Author
>>> class AuthorForm(ModelForm):
...     class Meta:
...         model = Author
...         localized_fields = ('birth_date',)

यदि localized_fields को विशेष मान '__all__' सेट किया जाता है, तो सभी फ़ील्ड स्थानीयकृत हो जाएंगे।

रूप विरासत

मूल रूपों के साथ, आप उन्हें विरासत में प्राप्त करके ModelForms विस्तार और पुन: उपयोग कर सकते हैं। यह उपयोगी है यदि आपको मॉडल से प्राप्त कई रूपों में उपयोग के लिए मूल फ़ील्ड पर अतिरिक्त फ़ील्ड या अतिरिक्त विधियों की घोषणा करने की आवश्यकता है। उदाहरण के लिए, पिछले ArticleForm वर्ग का उपयोग कर:

>>> class EnhancedArticleForm(ArticleForm):
...     def clean_pub_date(self):
...         ...

यह एक ऐसा रूप बनाता है जो कि pub_date लिए समान रूप से व्यवहार करता है, सिवाय इसके कि कुछ अतिरिक्त सत्यापन और pub_date फ़ील्ड के लिए सफाई हो।

यदि आप Meta.fields या Meta.exclude सूचियों को बदलना चाहते हैं, तो आप माता-पिता के Meta इनर वर्ग को भी Meta.fields कर Meta.exclude हैं:

>>> class RestrictedArticleForm(EnhancedArticleForm):
...     class Meta(ArticleForm.Meta):
...         exclude = ('body',)

यह एन्हांटेडएर्टिकलफॉर्म से अतिरिक्त विधि जोड़ता है और एक क्षेत्र को हटाने के लिए मूल ArticleForm.Meta को संशोधित करता है।

हालाँकि ध्यान देने योग्य बातें हैं।

  • सामान्य पायथन नाम संकल्प नियम लागू होते हैं। यदि आपके पास कई बेस क्लास हैं जो Meta इनर क्लास घोषित करते हैं, तो केवल पहले वाले का उपयोग किया जाएगा। इसका मतलब बच्चे का Meta , अगर यह मौजूद है, अन्यथा पहले माता-पिता का Meta आदि।
  • यह एक साथ Form और ModelForm दोनों से इनहेरिट करना संभव है, हालांकि, आपको यह सुनिश्चित करना होगा कि ModelForm एमआरओ में पहले दिखाई देता है। ऐसा इसलिए है क्योंकि ये कक्षाएं अलग-अलग मेटाक्लासेस पर निर्भर करती हैं और एक क्लास में केवल एक ही मेटाक्लास हो सकता है।
  • मूल रूप से मूल श्रेणी से विरासत में मिली Field को नाम से हटाकर संभव है कि नाम None उपवर्ग पर न हो।

    आप इस तकनीक का उपयोग केवल मूल वर्ग द्वारा घोषित रूप से परिभाषित क्षेत्र से बाहर निकलने के लिए कर सकते हैं; यह ModelForm मेटाक्लस को डिफ़ॉल्ट फ़ील्ड बनाने से नहीं रोकेगा। डिफ़ॉल्ट फ़ील्ड से ऑप्ट-आउट करने के लिए, उपयोग करने के लिए फ़ील्ड का चयन करना देखें।

प्रारंभिक मूल्य प्रदान करना

नियमित रूप के रूप में, प्रपत्र को तत्काल करते समय initial पैरामीटर निर्दिष्ट करके रूपों के लिए प्रारंभिक डेटा निर्दिष्ट करना संभव है। इस तरह से प्रदान किए गए प्रारंभिक मूल्य फॉर्म फ़ील्ड से प्रारंभिक मान और संलग्न मॉडल उदाहरण से मान दोनों को ओवरराइड करेंगे। उदाहरण के लिए:

>>> article = Article.objects.get(pk=1)
>>> article.headline
'My headline'
>>> form = ArticleForm(initial={'headline': 'Initial headline'}, instance=article)
>>> form['headline'].value()
'Initial headline'

ModelForm कारखाने समारोह

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

>>> from django.forms import modelform_factory
>>> from myapp.models import Book
>>> BookForm = modelform_factory(Book, fields=("author", "title"))

इसका उपयोग मौजूदा रूपों में सरल संशोधन करने के लिए भी किया जा सकता है, उदाहरण के लिए किसी दिए गए फ़ील्ड के लिए उपयोग किए जाने वाले विजेट को निर्दिष्ट करके:

>>> from django.forms import Textarea
>>> Form = modelform_factory(Book, form=BookForm,
...                          widgets={"title": Textarea()})

शामिल करने के लिए fields का उपयोग करके निर्दिष्ट किया जा सकता है और कीवर्ड तर्कों को exclude कर सकता है, या ModelForm इनर Meta क्लास पर संबंधित विशेषताओं को शामिल कर सकता है। कृपया प्रलेखन का उपयोग करने के लिए फ़ील्ड्स का चयन करते हुए ModelForm देखें।

... या विशिष्ट क्षेत्रों के लिए स्थानीयकरण सक्षम करें:

>>> Form = modelform_factory(Author, form=AuthorForm, localized_fields=("birth_date",))

मॉडल फॉर्मेट

class models.BaseModelFormSet

रेगुलर फॉर्मेट्स की तरह, Django एक बढ़ाया फॉर्मेट क्लास प्रदान करता है जो Django मॉडल के साथ काम करना आसान बनाता है। चलो ऊपर से Author मॉडल का पुन: उपयोग करें:

>>> from django.forms import modelformset_factory
>>> from myapp.models import Author
>>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))

fields का उपयोग केवल दिए गए फ़ील्ड का उपयोग करने के लिए फॉर्मेट को प्रतिबंधित करता है। वैकल्पिक रूप से, आप "ऑप्ट-आउट" तरीका अपना सकते हैं, यह निर्दिष्ट करते हुए कि किन क्षेत्रों को बाहर करना है:

>>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))

यह एक फॉर्मेट बनाएगा जो Author मॉडल से जुड़े डेटा के साथ काम करने में सक्षम है। यह एक नियमित फॉर्मेट की तरह काम करता है:

>>> formset = AuthorFormSet()
>>> print(formset)
<input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS"><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS"><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100"></td></tr>
<tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
<option value="" selected>---------</option>
<option value="MR">Mr.</option>
<option value="MRS">Mrs.</option>
<option value="MS">Ms.</option>
</select><input type="hidden" name="form-0-id" id="id_form-0-id"></td></tr>

ध्यान दें

modelformset_factory() formset_factory() उपयोग करता है। इसका मतलब यह है कि एक मॉडल फॉर्मेट एक मूल फॉर्मेट का एक विस्तार है जो जानता है कि किसी विशेष मॉडल के साथ कैसे संपर्क किया जाए।

क्वेरी बदलना

डिफ़ॉल्ट रूप से, जब आप किसी मॉडल से एक Author.objects.all() , तो Author.objects.all() उपयोग करेगा जिसमें मॉडल में सभी ऑब्जेक्ट शामिल हैं (जैसे, Author.objects.all() )। आप इस व्यवहार को queryset तर्क का उपयोग करके ओवरराइड कर सकते हैं:

>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))

वैकल्पिक रूप से, आप एक self.queryset बना सकते हैं जो __init__ में self.queryset सेट करता है:

from django.forms import BaseModelFormSet
from myapp.models import Author

class BaseAuthorFormSet(BaseModelFormSet):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.queryset = Author.objects.filter(name__startswith='O')

उसके बाद, अपने BaseAuthorFormSet वर्ग को फ़ैक्टरी फ़ंक्शन में पास करें:

>>> AuthorFormSet = modelformset_factory(
...     Author, fields=('name', 'title'), formset=BaseAuthorFormSet)

यदि आप एक ऐसे फॉर्मेट को वापस करना चाहते हैं जिसमें मॉडल के किसी भी पूर्व-मौजूदा उदाहरण शामिल नहीं हैं, तो आप एक खाली क्वेरीसेट निर्दिष्ट कर सकते हैं:

>>> AuthorFormSet(queryset=Author.objects.none())

रूप बदलना

डिफ़ॉल्ट रूप से, जब आप modelformset_factory उपयोग करते हैं, तो modelform_factory() का उपयोग करके एक मॉडल रूप बनाया जाएगा। अक्सर, यह कस्टम मॉडल फ़ॉर्म निर्दिष्ट करने के लिए उपयोगी हो सकता है। उदाहरण के लिए, आप एक कस्टम मॉडल फ़ॉर्म बना सकते हैं जिसमें कस्टम सत्यापन है:

class AuthorForm(forms.ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title')

    def clean_name(self):
        # custom validation for the name field
        ...

फिर, फ़ैक्टरी फ़ंक्शन के लिए अपना मॉडल फ़ॉर्म पास करें:

AuthorFormSet = modelformset_factory(Author, form=AuthorForm)

कस्टम मॉडल फॉर्म को परिभाषित करना हमेशा आवश्यक नहीं होता है। modelformset_factory फ़ंक्शन में कई तर्क होते हैं जो modelform_factory से modelform_factory , जो नीचे वर्णित हैं।

विजेट के साथ फ़ॉर्म में उपयोग करने के लिए विजेट निर्दिष्ट करना

widgets पैरामीटर का उपयोग करते हुए, आप किसी विशेष क्षेत्र के लिए ModelForm के विजेट वर्ग को अनुकूलित करने के लिए मूल्यों का शब्दकोश निर्दिष्ट कर सकते हैं। यह उसी तरह से काम करता है जैसे किसी ModelForm के भीतरी Meta क्लास में widgets डिक्शनरी काम करती है:

>>> AuthorFormSet = modelformset_factory(
...     Author, fields=('name', 'title'),
...     widgets={'name': Textarea(attrs={'cols': 80, 'rows': 20})})

खेतों के लिए स्थानीयकरण को सक्षम करना localized_fields साथ

स्थानीयकृत_ फ़ील्ड्स पैरामीटर का उपयोग करके, आप प्रपत्र में फ़ील्ड के लिए स्थानीयकरण सक्षम कर सकते हैं।

>>> AuthorFormSet = modelformset_factory(
...     Author, fields=('name', 'title', 'birth_date'),
...     localized_fields=('birth_date',))

यदि localized_fields को विशेष मान '__all__' सेट किया जाता है, तो सभी फ़ील्ड स्थानीयकृत हो जाएंगे।

प्रारंभिक मूल्य प्रदान करना

नियमित फॉर्मेट्स के साथ, प्रारंभिक स्वरूप निर्दिष्ट करके फॉर्मेट में प्रारंभिक डेटा निर्दिष्ट करना संभव है जब modelformset_factory() क्लास को modelformset_factory() द्वारा वापस लाया जाता है। हालांकि, मॉडल फॉर्मेट्स के साथ, प्रारंभिक मूल्य केवल अतिरिक्त रूपों पर लागू होते हैं, जो एक मौजूदा मॉडल उदाहरण से संलग्न नहीं हैं। यदि आरंभिक डेटा वाले अतिरिक्त फॉर्म उपयोगकर्ता द्वारा नहीं बदले जाते हैं, तो उन्हें मान्य या सहेजा नहीं जाएगा।

फॉर्मेट में वस्तुओं को सहेजना

एक ModelForm साथ, आप डेटा को मॉडल ऑब्जेक्ट के रूप में सहेज सकते हैं। यह फॉर्मेट की save() विधि से किया जाता है:

# Create a formset instance with POST data.
>>> formset = AuthorFormSet(request.POST)

# Assuming all is valid, save the data.
>>> instances = formset.save()

save() विधि डेटाबेस में सहेजे गए इंस्टेंस को लौटाता है। यदि किसी दिए गए इंस्टेंस का डेटा बाउंड डेटा में नहीं बदला है, तो इंस्टेंस को डेटाबेस में सहेजा नहीं जाएगा और रिटर्न वैल्यू ( instances में, उपरोक्त उदाहरण में) को शामिल नहीं किया जाएगा।

जब फ़ील्ड फ़ॉर्म से गायब हो जाते हैं (उदाहरण के लिए क्योंकि उन्हें बाहर रखा गया है), तो इन फ़ील्ड्स को save() विधि द्वारा सेट नहीं किया जाएगा। आप इस प्रतिबंध के बारे में अधिक जानकारी प्राप्त कर सकते हैं, जो नियमित ModelForms लिए भी है, उपयोग करने के लिए खेतों का चयन करने में

पास commit=False बिना सहेजे मॉडल के उदाहरणों को वापस करने के लिए commit=False :

# don't save to the database
>>> instances = formset.save(commit=False)
>>> for instance in instances:
...     # do something with instance
...     instance.save()

यह आपको डेटाबेस को सहेजने से पहले इंस्टेंस पर डेटा संलग्न करने की क्षमता देता है। यदि आपके फॉर्मेट में एक formset.save_m2m() होता है, तो आपको यह सुनिश्चित करने के लिए कि कई-से-कई रिश्तों को ठीक से सहेजने के लिए भी formset.save_m2m() कॉल करना होगा।

कॉल save() बाद, आपके मॉडल फॉर्मेट में तीन नए गुण होंगे जिनमें फॉर्मेट के परिवर्तन शामिल हैं:

models.BaseModelFormSet.changed_objects
models.BaseModelFormSet.deleted_objects
models.BaseModelFormSet.new_objects

संपादन योग्य वस्तुओं की संख्या को सीमित करना

नियमित फॉर्मेट्स के साथ, आप प्रदर्शित किए जाने वाले अतिरिक्त रूपों की संख्या को सीमित करने के लिए modelformset_factory() लिए max_num और extra मापदंडों का उपयोग कर सकते हैं।

max_num मौजूदा ऑब्जेक्ट्स को प्रदर्शित होने से नहीं रोकता है:

>>> Author.objects.order_by('name')
<QuerySet [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]>

>>> AuthorFormSet = modelformset_factory(Author, fields=('name',), max_num=1)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> [x.name for x in formset.get_queryset()]
['Charles Baudelaire', 'Paul Verlaine', 'Walt Whitman']

इसके अलावा, extra=0 नए मॉडल उदाहरणों के निर्माण को नहीं रोकता है क्योंकि आप जावास्क्रिप्ट के साथ अतिरिक्त रूप जोड़ सकते हैं या केवल अतिरिक्त POST डेटा भेज सकते हैं । फ़ॉर्मेट अभी तक "केवल संपादित करें" दृश्य के लिए कार्यक्षमता प्रदान नहीं करते हैं जो नए उदाहरणों के निर्माण को रोकता है।

यदि max_num का मान मौजूदा संबंधित वस्तुओं की संख्या से अधिक है, तो extra अतिरिक्त रिक्त प्रपत्रों को max_num में जोड़ा जाएगा, इसलिए जब तक कि कुल रूपों की संख्या max_num से अधिक न हो:

>>> AuthorFormSet = modelformset_factory(Author, fields=('name',), max_num=4, extra=2)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100"><input type="hidden" name="form-0-id" value="1" id="id_form-0-id"></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100"><input type="hidden" name="form-1-id" value="3" id="id_form-1-id"></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100"><input type="hidden" name="form-2-id" value="2" id="id_form-2-id"></td></tr>
<tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100"><input type="hidden" name="form-3-id" id="id_form-3-id"></td></tr>

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

एक दृश्य में एक मॉडल फॉर्मेट का उपयोग करना

मॉडल फॉर्मेट्स फॉर्मेट्स के समान हैं। मान लें कि हम Author मॉडल उदाहरणों को संपादित करने के लिए एक फॉर्मेट प्रस्तुत करना चाहते हैं:

from django.forms import modelformset_factory
from django.shortcuts import render
from myapp.models import Author

def manage_authors(request):
    AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
    if request.method == 'POST':
        formset = AuthorFormSet(request.POST, request.FILES)
        if formset.is_valid():
            formset.save()
            # do something.
    else:
        formset = AuthorFormSet()
    return render(request, 'manage_authors.html', {'formset': formset})

जैसा कि आप देख सकते हैं, एक मॉडल फॉर्मेट का व्यू लॉजिक "सामान्य" फॉर्मेट की तुलना में बहुत भिन्न नहीं है। अंतर केवल इतना है कि हम डेटाबेस में डेटा को बचाने के लिए formset.save() कहते हैं। (यह ऊपर वर्णित किया गया था, फॉर्मेट में वस्तुओं को सहेजते हुए ।)

एक ModelFormSet पर ओवरराइडिंग clean()

जैसे ModelForms साथ, डिफ़ॉल्ट रूप से एक ModelFormSet की clean() विधि यह प्रमाणित करेगी कि unique_together की कोई भी वस्तु आपके मॉडल पर अद्वितीय अवरोधों का उल्लंघन नहीं करती है (या तो unique , unique या unique_for_date|month|year )। यदि आप किसी ModelFormSet पर clean() विधि को ओवरराइड करना चाहते हैं और इस सत्यापन को बनाए रखना चाहते हैं, तो आपको पैरेंट क्लास की clean विधि को कॉल करना होगा:

from django.forms import BaseModelFormSet

class MyModelFormSet(BaseModelFormSet):
    def clean(self):
        super().clean()
        # example custom validation across forms in the formset
        for form in self.forms:
            # your custom formset validation
            ...

यह भी ध्यान दें कि जब तक आप इस चरण तक पहुंचते हैं, तब तक प्रत्येक Form के लिए व्यक्तिगत मॉडल उदाहरण पहले ही बनाए जा चुके हैं। form.cleaned_data सहेजे गए मूल्य को प्रभावित करने के लिए एक मान को संशोधित करना पर्याप्त नहीं है। यदि आप एक मूल्य संशोधित करना चाहते हैं तो आपको संशोधित ModelFormSet.clean() करना होगा form.instance :

from django.forms import BaseModelFormSet

class MyModelFormSet(BaseModelFormSet):
    def clean(self):
        super().clean()

        for form in self.forms:
            name = form.cleaned_data['name'].upper()
            form.cleaned_data['name'] = name
            # update the instance value.
            form.instance.name = name

कस्टम क्वेरी का उपयोग करना

जैसा कि पहले कहा गया है, आप मॉडल फॉर्मेट द्वारा उपयोग की जाने वाली डिफ़ॉल्ट क्वेरी को ओवरराइड कर सकते हैं:

from django.forms import modelformset_factory
from django.shortcuts import render
from myapp.models import Author

def manage_authors(request):
    AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
    if request.method == "POST":
        formset = AuthorFormSet(
            request.POST, request.FILES,
            queryset=Author.objects.filter(name__startswith='O'),
        )
        if formset.is_valid():
            formset.save()
            # Do something.
    else:
        formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
    return render(request, 'manage_authors.html', {'formset': formset})

ध्यान दें कि हम इस उदाहरण में और मामलों queryset दोनों में तर्क पास करते हैं । POST GET

टेम्पलेट में फॉर्मेट का उपयोग करना

एक Django टेम्पलेट में एक फॉर्मेट को प्रस्तुत करने के तीन तरीके हैं।

सबसे पहले, आप फॉर्मेट को अधिकतर काम करने दे सकते हैं:

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

दूसरा, आप मैन्युअल रूप से फ़ॉर्मेट को प्रस्तुत कर सकते हैं, लेकिन फ़ॉर्म को स्वयं से निपटने दें:

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

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

तीसरा, आप प्रत्येक क्षेत्र को मैन्युअल रूप से प्रस्तुत कर सकते हैं:

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

यदि आप इस तीसरी विधि का उपयोग करने का विकल्प चुनते हैं और आप {% for %} लूप के साथ फ़ील्ड पर पुनरावृति नहीं करते हैं , तो आपको प्राथमिक कुंजी फ़ील्ड को प्रस्तुत करना होगा। उदाहरण के लिए, यदि आप एक मॉडल के क्षेत्र name और प्रतिपादन कर रहे थे age :

<form method="post">
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form.id }}
        <ul>
            <li>{{ form.name }}</li>
            <li>{{ form.age }}</li>
        </ul>
    {% endfor %}
</form>

ध्यान दें कि हमें कैसे स्पष्ट रूप से प्रस्तुत करने की आवश्यकता है {{ form.id }} । यह सुनिश्चित करता है कि POST मामले में मॉडल फॉर्मेट सही तरीके से काम करेगा। (यह उदाहरण एक प्राथमिक कुंजी को नामित करता है id । यदि आपने स्पष्ट रूप से अपनी स्वयं की प्राथमिक कुंजी को परिभाषित किया है जिसे नहीं कहा जाता है id , तो सुनिश्चित करें कि यह प्रदान की गई है।

इनलाइन फॉर्मेट्स

class models.BaseInlineFormSet

इनलाइन फॉर्मेट्स मॉडल फॉर्मेट्स के शीर्ष पर एक छोटी सी अमूर्त परत है। ये एक विदेशी कुंजी के माध्यम से संबंधित वस्तुओं के साथ काम करने के मामले को सरल बनाते हैं। मान लीजिए कि आपके पास ये दो मॉडल हैं:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)

यदि आप एक फॉर्मेट बनाना चाहते हैं जो आपको किसी विशेष लेखक से संबंधित पुस्तकों को संपादित करने की अनुमति देता है, तो आप ऐसा कर सकते हैं:

>>> from django.forms import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book, fields=('title',))
>>> author = Author.objects.get(name='Mike Royko')
>>> formset = BookFormSet(instance=author)

BookFormSet का prefix है 'book_set' ( <model name>_set )। तो Book के ForeignKey लिए Author एक है related_name , कि बजाय प्रयोग किया जाता है।

ध्यान दें

inlineformset_factory() उपयोग modelformset_factory() और निशान can_delete=True

ओवरराइड करने के तरीके a InlineFormSet

जब तरीकों पर काबू पाने InlineFormSet , तुम BaseInlineFormSet बजाय उपवर्ग चाहिए BaseModelFormSet

उदाहरण के लिए, यदि आप ओवरराइड करना चाहते हैं clean() :

from django.forms import BaseInlineFormSet

class CustomInlineFormSet(BaseInlineFormSet):
    def clean(self):
        super().clean()
        # example custom validation across forms in the formset
        for form in self.forms:
            # your custom formset validation
            ...

एक मॉडलफ़ॉर्मसेट पर ओवरराइडिंग क्लीन () भी देखें ।

फिर जब आप अपना इनलाइन फॉर्मेट बनाते हैं, तो वैकल्पिक तर्क में पास करें formset :

>>> from django.forms import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book, fields=('title',),
...     formset=CustomInlineFormSet)
>>> author = Author.objects.get(name='Mike Royko')
>>> formset = BookFormSet(instance=author)

एक ही मॉडल के लिए एक से अधिक विदेशी कुंजी

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

class Friendship(models.Model):
    from_friend = models.ForeignKey(
        Friend,
        on_delete=models.CASCADE,
        related_name='from_friends',
    )
    to_friend = models.ForeignKey(
        Friend,
        on_delete=models.CASCADE,
        related_name='friends',
    )
    length_in_months = models.IntegerField()

इसके समाधान के लिए, आप उपयोग कर सकते हैं fk_name करने के लिए inlineformset_factory() :

>>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name='from_friend',
...     fields=('to_friend', 'length_in_months'))

एक दृश्य में इनलाइन फॉर्मेट का उपयोग करना

आप एक ऐसा दृश्य प्रदान करना चाह सकते हैं जो उपयोगकर्ता को किसी मॉडल से संबंधित वस्तुओं को संपादित करने की अनुमति देता है। यहां बताया गया है कि आप ऐसा कैसे कर सकते हैं:

def manage_books(request, author_id):
    author = Author.objects.get(pk=author_id)
    BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',))
    if request.method == "POST":
        formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
        if formset.is_valid():
            formset.save()
            # Do something. Should generally end with a redirect. For example:
            return HttpResponseRedirect(author.get_absolute_url())
    else:
        formset = BookInlineFormSet(instance=author)
    return render(request, 'manage_books.html', {'formset': formset})

ध्यान दें कि हम instance दोनों POST और GET मामलों में कैसे गुजरते हैं।

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

inlineformset_factory का उपयोग करता है modelformset_factory और इसके अधिकांश तर्कों को पास करता है modelformset_factory । इसका मतलब है कि आप widgets पैरामीटर को उसी तरह से उपयोग कर सकते हैं जैसे इसे पास करने के लिए modelformset_factory । ऊपर दिए गए विजेट के साथ फ़ॉर्म में उपयोग करने के लिए विशिष्ट विजेट देखें ।

Original text