एक django ModelForm में कई मॉडल?


98

क्या ModelFormdjango में एकल में कई मॉडल शामिल करना संभव है ? मैं एक प्रोफ़ाइल संपादन फ़ॉर्म बनाने की कोशिश कर रहा हूं। इसलिए मुझे उपयोगकर्ता मॉडल और उपयोगकर्ताप्रोफ़ाइल मॉडल से कुछ फ़ील्ड शामिल करने की आवश्यकता है । वर्तमान में मैं इस तरह के 2 रूपों का उपयोग कर रहा हूं

class UserEditForm(ModelForm):

    class Meta:
        model = User
        fields = ("first_name", "last_name")

class UserProfileForm(ModelForm):

    class Meta:
        model = UserProfile
        fields = ("middle_name", "home_phone", "work_phone", "cell_phone")

क्या इन्हें एक रूप में समेकित करने का कोई तरीका है या क्या मुझे केवल एक प्रपत्र बनाने और db को लोड करने और खुद को बचाने की आवश्यकता है?


जवाबों:


93

आप बस एक <form>HTML एलिमेंट के अंदर टेम्प्लेट में दोनों फॉर्म दिखा सकते हैं । फिर बस व्यू में अलग से फॉर्म प्रोसेस करें। आप अभी भी उपयोग कर पाएंगे form.save()और डीबी लोड करने और खुद को बचाने की प्रक्रिया नहीं कर पाएंगे ।

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


यह सलाह का एक अच्छा टुकड़ा है, लेकिन ऐसे मामले हैं जो लागू नहीं होते हैं, उदाहरण के लिए। एक स्वरूप के लिए कस्टम मॉडल फार्म।
Wtower

8
एक वर्ग आधारित दृश्य को एक से अधिक रूपों और एक टेम्पलेट को दिखाने में सक्षम बनाने के लिए एक सीधा रास्ता क्या होगा जो उन्हें एक ही <form>तत्व में जोड़ता है ?
jozxyqk

1
पर कैसे? आमतौर पर FormViewकेवल एक ही form_classइसे सौंपा जाता है।
एरिकबवर्क

@erikbwork आपको इस मामले के लिए फॉर्म व्यू का उपयोग नहीं करना चाहिए। बस उपवर्ग TemplateViewऔर FormView के रूप में एक ही तर्क को लागू करें, लेकिन कई रूपों के साथ।
मोपाग

10

आप कोड के इस टुकड़े का उपयोग करने का प्रयास कर सकते हैं:

class CombinedFormBase(forms.Form):
    form_classes = []

    def __init__(self, *args, **kwargs):
        super(CombinedFormBase, self).__init__(*args, **kwargs)
        for f in self.form_classes:
            name = f.__name__.lower()
            setattr(self, name, f(*args, **kwargs))
            form = getattr(self, name)
            self.fields.update(form.fields)
            self.initial.update(form.initial)

    def is_valid(self):
        isValid = True
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            if not form.is_valid():
                isValid = False
        # is_valid will trigger clean method
        # so it should be called after all other forms is_valid are called
        # otherwise clean_data will be empty
        if not super(CombinedFormBase, self).is_valid() :
            isValid = False
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            self.errors.update(form.errors)
        return isValid

    def clean(self):
        cleaned_data = super(CombinedFormBase, self).clean()
        for f in self.form_classes:
            name = f.__name__.lower()
            form = getattr(self, name)
            cleaned_data.update(form.cleaned_data)
        return cleaned_data

उदाहरण उपयोग:

class ConsumerRegistrationForm(CombinedFormBase):
    form_classes = [RegistrationForm, ConsumerProfileForm]

class RegisterView(FormView):
    template_name = "register.html"
    form_class = ConsumerRegistrationForm

    def form_valid(self, form):
        # some actions...
        return redirect(self.get_success_url())

ऐसा लगता है कि कुछ स्पष्ट जाँच के कारण व्यवस्थापक में उपयोग नहीं किया जा सकता है:admin.E016) The value of 'form' must inherit from 'BaseModelForm'.
WhyNotHugo

मैं इसके साथ कैसे उपयोग कर सकता हूं UpdateView?
पावेल श्लेपनेव

3

erikbwork और मुझे दोनों की समस्या थी कि कोई केवल एक मॉडल को सामान्य क्लास बेस्ड व्यू में शामिल कर सकता है। मैंने इसे मियाओ की तरह आने का एक समान तरीका पाया, लेकिन अधिक मॉड्यूलर।

मैंने एक मिक्सिन लिखा है ताकि आप सभी सामान्य क्लास बेस्ड व्यू का उपयोग कर सकें। मॉडल, फ़ील्ड्स और अब child_model और child_field को भी परिभाषित करें - और फिर आप Zach के वर्णन जैसे टैग में दोनों मॉडलों के क्षेत्र लपेट सकते हैं।

class ChildModelFormMixin: 
    ''' extends ModelFormMixin with the ability to include ChildModelForm '''
    child_model = ""
    child_fields = ()
    child_form_class = None

    def get_child_model(self):
        return self.child_model

    def get_child_fields(self):
        return self.child_fields

    def get_child_form(self):
        if not self.child_form_class:
            self.child_form_class = model_forms.modelform_factory(self.get_child_model(), fields=self.get_child_fields())
        return self.child_form_class(**self.get_form_kwargs())

    def get_context_data(self, **kwargs):
        if 'child_form' not in kwargs:
            kwargs['child_form'] = self.get_child_form()
        return super().get_context_data(**kwargs)

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        child_form = self.get_child_form()

        # check if both forms are valid
        form_valid = form.is_valid()
        child_form_valid = child_form.is_valid()

        if form_valid and child_form_valid:
            return self.form_valid(form, child_form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form, child_form):
        self.object = form.save()
        save_child_form = child_form.save(commit=False)
        save_child_form.course_key = self.object
        save_child_form.save()

        return HttpResponseRedirect(self.get_success_url())

उदाहरण उपयोग:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_fields = ('payment_token', 'cart',)

या ModelFormClass के साथ:

class ConsumerRegistrationUpdateView(UpdateView):
    model = Registration
    fields = ('firstname', 'lastname',)
    child_model = ConsumerProfile
    child_form_class = ConsumerProfileForm

किया हुआ। आशा है कि किसी की मदद करता है।


इसमें save_child_form.course_key = self.object, क्या है .course_key?
एडम स्टार्र जूल

मुझे लगता है कि course_key संबंधित मॉडल है, मेरे मामले में UserProfile.user के रूप में "उपयोगकर्ता" है जो कि एक बैकएफ़ है, हो सकता है कि फ़ील्ड का नाम अनुकूलन योग्य होना चाहिए यदि यह फिर से उपयोग करने योग्य मिक्सिन हो। लेकिन मुझे अभी भी एक और मुद्दा मिल रहा है जहां बच्चे का रूप वास्तव में प्रारंभिक डेटा के साथ आबादी नहीं है, उपयोगकर्ता से सभी फ़ील्ड पूर्व-आबादी वाले हैं, लेकिन उपयोगकर्ताप्रोफाइल के लिए नहीं। मुझे पहले इसे ठीक करना पड़ सकता है।
रोबडल

यह समस्या कि चाइल्ड फॉर्म क्यों पॉप्युलेट नहीं होता है क्योंकि get_child_form मेथड में यह कॉल करता है, return self.child_form_class(**self.get_form_kwargs())लेकिन इसमें गलत मॉडल इंस्टेंस मिलता है kwargs['instance'], उदाहरण के लिए मुख्य मॉडल है न कि चाइल्ड मॉडल। ठीक करने के लिए आपको पहले एक चर में kwargs बचाने की आवश्यकता है kwargs = self.get_form_kwargs()फिर kwargs['initial']कॉल करने से पहले सही मॉडल उदाहरण के साथ अद्यतन करें return self.child_form_class(**kwargs)। मेरे मामले में kwargs['instance'] = kwargs['instance'].profileअगर यह समझ में आता है।
रोबडल

दुर्भाग्य से बचाने पर यह अभी भी दो स्थानों पर दुर्घटनाग्रस्त हो जाएगा, एक जहाँ self.object अभी तक form_valid में नहीं है, इसलिए यह एक AttrourError फेंकता है, और दूसरी जगह उदाहरण नहीं है। मुझे यकीन नहीं है कि अगर यह समाधान पोस्ट किए जाने से पहले पूरी तरह से परीक्षण किया गया था, तो कम्बाइंडफॉर्मबेस का उपयोग करके अन्य उत्तर के साथ जाना बेहतर हो सकता है।
रोबडल

1
क्या है model_forms?
दादी चाची

2

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


1
इनलाइन फॉर्मेट्स का उपयोग तब किया जाता है जब आपको एक से कई संबंधों के साथ काम करने की आवश्यकता होती है। जैसे कि एक कंपनी जहां आप कर्मचारियों को जोड़ते हैं। मैं एक एकल रूप में 2 तालिकाओं को संयोजित करने का प्रयास कर रहा हूं। यह एक से एक संबंध है।
जेसन वेब

इनलाइन फॉर्मेट का उपयोग काम करेगा, लेकिन आदर्श से कम होने की संभावना है। आप एक मॉडल भी बना सकते हैं जो आपके लिए संबंध को संभालता है, और फिर एकल रूप का उपयोग करें। के रूप में सुझाव में सिर्फ 2 रूपों के साथ एक ही पृष्ठ होने stackoverflow.com/questions/2770810/... काम करेगा।
जॉन पेरिवल हैकवर्थ

2

इसी तरह की समस्या के लिए आप यहां मेरे उत्तर की जांच कर सकते हैं ।

यह पंजीकरण और उपयोगकर्ता प्रोफ़ाइल को एक रूप में संयोजित करने के बारे में बात करता है, लेकिन इसे किसी भी मॉडलफ़ॉर्म संयोजन के लिए सामान्यीकृत किया जा सकता है।


0

मैंने django betterforms के MultiForm और MultiModelForm का उपयोग किया अपने प्रोजेक्ट में किया। कोड में सुधार किया जा सकता है, यद्यपि। उदाहरण के लिए, यह django.six पर निर्भर है, जो 3. + द्वारा समर्थित नहीं है, लेकिन ये सभी आसानी से तय किए जा सकते हैं

यह प्रश्न स्टैकऑवरफ्लो में कई बार दिखाई दिया है , इसलिए मुझे लगता है कि यह इसके साथ मुकाबला करने का एक मानकीकृत तरीका खोजने का समय है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.