2010-04-27 9 views
5

मेरे पास मॉडल मॉडल पर समान एम 2 एम फ़ील्ड के साथ दो मॉडल (मॉडलपेरेंट और मॉडल चाइल्ड) हैं। मॉडल चाइल्ड मॉडलपैंट पर एक विदेशी कुंजी है और मॉडल चाइल्ड को व्यवस्थापक पृष्ठ पर मॉडलपेरेंट के लिए इनलाइन के रूप में परिभाषित किया गया है।django - मॉडलएडमिन और इसकी इनलाइनों को कैसे पार करें?

### models.py ### 
    class Subject(Models.Model): 
    pass 

    class ModelParent(models.Model): 
    subjects_parent = ManyToManyField(Subject) 

    class ModelChild(models.Model): 
    parent = ForeignKey(ModelParent) 
    subjects_child = ManyToManyField(Subject) 

### admin.py ### 
    class ModelChildInline(admin.TabularInline): 
     model = ModelChild 

    class ModelParentAdmin(admin.ModelAdmin): 
    inlines = [ModelChildInline] 

    admin.site.register(ModelParent, ModelParentAdmin) 

मैं एक महत्वपूर्ण प्रतिबंध हालांकि है, ModelChild के subjects_child क्षेत्र किसी भी विषय है कि subject_parent अपने subjects_parent के साथ करता है को संदर्भित नहीं करना चाहिए।

तो, यदि मैं दोनों मॉडलों के लिए व्यवस्थापक पृष्ठ पर एक ही विषय (subject_parent और subject_child में) का चयन करता हूं, तो मैं इसे कैसे सत्यापित कर सकता हूं? यदि केवल एक फ़ील्ड बदलता है तो आप इसे डीबी के खिलाफ मान्य करते हैं, लेकिन क्या होगा यदि दोनों बदलते हैं (subject_parent और subject_child)? बचत से पहले दोनों रूपों को एक साथ कैसे सत्यापित कर सकता हूं?

+0

फॉर्म के लिए स्वच्छ() में इसे मान्य क्यों न करें, फ़ील्ड_ स्पेसिफिक क्लीन नहीं? इस तरह, आपको जिन क्षेत्रों को जांचना होगा, उन्हें पहले से साफ़ कर दिया जाएगा। केवल एक चीज मुझे यकीन नहीं है कि क्या आप डेटा के दोनों सेट तक पहुंच सकते हैं, या केवल मॉडल में माता-पिता के लिए डेटा() ... –

+1

सुझाव के लिए Thx। मैंने पहले से ही ऐसा किया है, लेकिन रूपों के साथ मैं केवल मुख्य रूप (मॉडलपेरेंट एडमिन के लिए फॉर्म) को मान्य कर सकता हूं और फॉर्मेट को अलग-अलग (केवल डीबी के खिलाफ) में जोड़ सकता हूं। एकमात्र जगह जो मैं उन्हें एक साथ एक्सेस कर सकता हूं वह ModelParentAdmin क्लास में है। लेकिन उस वर्ग में एक साफ() विधि नहीं है। मैं इस वर्ग की save_formsets (...) विधि में svaing से पहले उन्हें मान्य कर सकता हूं, लेकिन raise पर प्रमाणीकरण त्रुटि ("त्रुटि") कुछ भी इसे पकड़ नहीं लेता है। – blazt

उत्तर

5

मैं ModelAdminWithInline नामक एक नया वर्ग admin.ModelAdmin से विरासत में मिली और तरीकों add_view (...) और change_view (...) समारोह is_cross_valid (स्वयं, प्रपत्र, formsets) कॉल करने के लिए संशोधित किया है, जहां आप सभी रूपों को एक साथ मान्य कर सकते हैं। दोनों कार्यों के लिए किया था:

#... 
formsets_validated = all_valid(formsets) 
cross_validated = self.is_cross_valid(form, formsets) 
if formsets_validated and form_validated and cross_validated: 
#... 

नए कार्य is_cross_valid (...) इस तरह परिभाषित किया गया है:

def is_cross_valid(self, form, formsets): 
    return True 

तो नया वर्ग वास्तव में काम करना चाहिए

#... 
if all_valid(formsets) and form_validated: 
#... 

करने के लिए बदल ModelAdmin के समान है यदि आप is_cross_valid (...) फ़ंक्शन नहीं बदलते हैं।

अब मेरी admin.py इस तरह दिखता है:

###admin.py### 
class ModelAdminWithInline(admin.ModelAdmin): 
    def is_cross_valid(self, form, formsets): 
    return True 

    def add_view(self, request, form_url='', extra_context=None): 
    #modified code 

    def change_view(self, request, object_id, extra_context=None): 
    #modified code 

class ModelChildInline(admin.TabularInline): 
    model = ModelChild 

class ModelParentAdmin(ModelAdminWithInline): 
    inlines = [ModelChildInline] 

    def is_cross_valid(self, form, formsets): 
    #Do some cross validation on forms 
    #For example, here is my particular validation: 
    valid = True 

    if hasattr(form, 'cleaned_data'): 

     subjects_parent = form.cleaned_data.get("subjects_parent") 

     #You can access forms from formsets like this: 
     for formset in formsets: 
     for formset_form in formset.forms: 
      if hasattr(formset_form, 'cleaned_data'): 

      subjects_child = formset_form.cleaned_data.get("subjects_child") 
      delete_form = formset_form.cleaned_data.get("DELETE") 

      if subjects_child and (delete_form == False): 
       for subject in subjects_child: 
       if subject in subjects_parent: 
        valid = False 
        #From here you can still report errors like in regular forms: 
        if "subjects_child" in formset_form.cleaned_data.keys(): 
        formset_form._errors["subjects_child"] = ErrorList([u"Subject %s is already selected in parent ModelParent" % subject]) 
        del formset_form.cleaned_data["subjects_child"] 
        else: 
        formset_form._errors["subjects_child"] += ErrorList(u"Subject %s is already selected in parent ModelParent" % subject]) 

     #return True on success or False otherwise. 
     return valid 

admin.site.register(ModelParent, ModelParentAdmin) 

समाधान एक छोटा सा hackish है, लेकिन यह काम करता है :)। त्रुटियां नियमित मॉडलफॉर्म और मॉडलएडमिन कक्षाओं के समान दिखाई देती हैं। Django 1.2 (जिसे जल्द ही रिलीज़ किया जाना चाहिए) में मॉडल सत्यापन होना चाहिए, इसलिए मुझे आशा है कि तब इस समस्या को और अधिक अच्छी तरह से हल किया जा सकता है।

2

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

class SomeForm(ModelForm): 
    #some code 
    def clean(self): 
    #some code 
class SomeAdminClass(ModelAdmin): 
#some code 
form = SomeForm 
#more code 
+2

मैंने पहले ही ऐसा किया है, लेकिन इसके साथ मैं केवल डीबी _separately_ के खिलाफ फॉर्म मान्य कर सकता हूं। क्या होगा यदि आप एक ही पृष्ठ पर ModelParent.subjects_parent और ModelChild.sujects_child पर एक ही विषय जोड़ते हैं (यह निश्चित रूप से इनलाइनों के साथ होता है)। एक रूप यह नहीं जानता कि दूसरे ने एक ही विषय का चयन किया है ताकि वे दोनों बच जाए। ऐसा इसलिए है क्योंकि डीबी में बचत से पहले दोनों रूपों का सत्यापन होता है, इसलिए उनमें से कोई भी अन्य परिवर्तनों को नहीं देखता है। – blazt

+0

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

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