2010-05-05 17 views
74

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

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") 

की तरह 2 रूपों का उपयोग कर रहा है कि वहाँ एक रूप में इन मजबूत करने के लिए एक रास्ता है या मैं सिर्फ एक रूप बना सकते हैं और डाटाबेस लोड हो रहा है संभाल करने की क्या ज़रूरत है और अपने आप को बचाने के?

+0

[Django: फ़ॉर्म का उपयोग कर एक टेम्पलेट में एकाधिक मॉडल] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/569468/django-multiple-models-in-one-template-using-forms) –

उत्तर

73

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

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

+0

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

+3

कक्षा आधारित दृश्य को एक से अधिक रूप और एक टेम्पलेट दिखाने में सक्षम बनाने का एक सीधा तरीका क्या होगा जो उसके बाद उन्हें '

'तत्व में जोड़ता है? – jozxyqk

+0

लेकिन कैसे? आम तौर पर 'फॉर्म व्यू' में केवल एक 'form_class' असाइन किया जाता है। – erikbwork

2

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

+0

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

+0

इनलाइन फॉर्मेट का उपयोग काम करेगा, लेकिन संभवतः आदर्श से कम होगा। आप एक मॉडल भी बना सकते हैं जो आपके लिए संबंध को संभालता है, और फिर एक ही फॉर्म का उपयोग करता है। Http://stackoverflow.com/questions/2770810/muliple-models-in-a-single-django-modelform/2774732#2774732 में सुझाए गए अनुसार 2 रूपों वाला एक पृष्ठ होना चाहिए। –

2

आप इसी समस्या के लिए my answer here देख सकते हैं।

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

5

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

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()) 
+0

ऐसा लगता है कि कुछ स्पष्ट चेक के कारण व्यवस्थापक में इसका उपयोग नहीं किया जा सकता है: 'admin.E016) 'फॉर्म' का मान 'बेसमोडेलफॉर्म' से प्राप्त होना चाहिए। ' – WhyNotHugo

2

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

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

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 

हो गया। उम्मीद है कि किसी की मदद करता है।

+0

इस' save_child_form.course_key = self.object' में , '.course_key' क्या है? –

संबंधित मुद्दे