2011-11-10 10 views
8

एक मॉडल MainModel नामित को देखते हुए और एक RelatedModel, जहां बाद में एक ForeignKey क्षेत्र MainModel गया है के आधार पर अलग अलग inlines दिखाने के लिए कैसे:वर्तमान वस्तु क्षेत्र मूल्य

class MainModel(models.Model): 
    name = models.CharField(max_length=50) 
    type = models.BooleanField() 

class RelatedModel1(models.Model): 
    main = models.ForeingKey(MainModel): 
    name = models.CharField(max_length=50) 

class RelatedModel2(models.Model): 
    main = models.ForeingKey(MainModel): 
    name = models.CharField(max_length=50) 

और इसी ModelAdmin कक्षाएं:

class RelatedModel1InlineAdmin(admin.TabularInline): 
    model = RelatedModel1 

class RelatedModel2InlineAdmin(admin.TabularInline): 
    model = RelatedModel2 

class MainModel(admin.ModelAdmin): 
    inlines = [RelatedModel1, RelatedModel2] 

और यह डिफ़ॉल्ट व्यवहार है, आपको प्रत्येक इनलाइन मॉडल के लिए दो इनलाइन मिलती हैं। सवाल पूरी तरह से सभी inlines छिपाने के बारे में जब MainModel उदाहरण RelatedModel2 जब के लिए बनाया जाता जा रहा है (ModelAdmin के add_view), और RelatedModel1 के लिए inlines दिखाने के लिए जब MainModel उदाहरण के type क्षेत्र True है, और दिखाने के inlines है False

मैं ModelAdmin.inline_instances विशेषता के लिए descriptor बनाने जा रहा था, लेकिन मुझे एहसास हुआ कि मुझे ऑब्जेक्ट इंस्टेंस को संपादित करने की आवश्यकता है, लेकिन इसे पैरामीटर के रूप में पारित किया गया है।

कोई मदद?

धन्यवाद!

+0

मैं जरूरत है कि कुछ समय पहले .. कभी नहीं जवाब है, अच्छा सवाल मिल गया! – juliomalegria

उत्तर

1

contrib.admin.options.py पर देखकर ऐसा लगता है कि आप ModelAdmin.get_formsets ओवरराइड कर सकते हैं। ध्यान दें कि व्यवस्थापक साइट self.inline_instances पर __init__ पर पॉप्युलेट करती है, इसलिए आप संभवत: अनुसरण करना चाहते हैं और अपनी इनलाइनों को तुरंत चालू नहीं करना चाहते हैं। मुझे यकीन है कि नहीं यह कैसे महंगा है कर रहा हूँ:)

def get_formsets(self, request, obj=None): 
    if not obj: 
     return [] # no inlines 

    elif obj.type == True: 
     return [MyInline1(self.model, self.admin_site).get_formset(request, obj)] 

    elif obj.type == False: 
     return [MyInline2(self.model, self.admin_site).get_formset(request, obj)] 

    # again, not sure how expensive MyInline(self.model, self.admin_site) is. 
    # the admin does this once. You could instantiate them and store them on the 
    # admin class somewhere to reference instead. 

मूल व्यवस्थापक get_formsets जनरेटर का उपयोग करता है - तुम भी अधिक बारीकी से मूल नकल करने के लिए किए जा सकेंगे:

def get_formsets(self, request, obj=None): 
    for inline in self.inline_instances: 
     yield inline.get_formset(request, obj) 
+0

यह पता चलता है कि यह काम नहीं करता है, क्योंकि यह मॉडलएडमिन के 'change_view' /' add_view' में है: 'फॉर्मसेट के लिए, ज़िप में इनलाइन (self.get_formsets (अनुरोध, obj), self.inline_instances):' इस प्रकार, एक सूची एक फॉर्मेट वापस कर दिया जाता है, लेकिन जब यह इनलाइनों की सूची के साथ "ज़िप" हो जाता है, तो हमेशा फॉर्मेट वापस सूची में पहली इनलाइन के अनुरूप नहीं होता है। –

+0

ओच, तुम सही हो! मुझे यकीन नहीं है कि मैं self.inline_instances कॉल के आस-पास एक अच्छा तरीका देखता हूं। एक समय में एक दृश्य प्रस्तुत करने के लिए एक ताला? :(डैंग। मैं वास्तव में इस विचार के बारे में बहुत उत्साहित था क्योंकि मैंने इसे अपने आप में चलाया है। –

+0

इसके बारे में क्या: 'get_formsets' को फॉर्मसेट उदाहरण वापस करना चाहिए, इसलिए, मूल्य से संबंधित नहीं हैं जो" अक्षम "करने के बारे में क्या है 'obj.type'? –

4

@Yuji 'Tomita' Tomitayou विचार अच्छा था, मेरे पास वही था लेकिन एक बार कोशिश कर रहा था, मुझे एहसास हुआ कि आपको self.inlines से विशिष्ट कुंजी को भी हटा देना चाहिए क्योंकि change_view और add_view विधि self.get_inline_instances(request)get_formsets() से पहले कहा जाता है। इसलिए मैंने इनलाइनों को get_form() विधि में संभाला।

यहाँ है मैं कैसे सफलतापूर्वक ऐसा किया:

class SampleAdmin(ModelAdmin): 
    inlines = [] 

    def get_inlines(self): 
     return [SampleInline, SampleInline2] 

    def get_form(self, request, obj=None, **kwargs): 
     # due to django admin form fields caching you must 
     # redefine inlines on every `get_form()` call 
     if (obj): self.inlines = self.get_inlines() 
     for inline in self.inlines: 
      # Here change condition based on your needs and manipulate 
      # self.inlines as you like (remove, change, etc). 
      # I used inline.__name__ to detect if this is correct inline 
      # for my obj 
      if obj.CONDITION: 
       self.inlines.remove(inline) 
     return super(SampleAdmin, self).get_form(request, obj, **kwargs) 
0

यहाँ कोड का एक टुकड़ा मैंने लिखा है जब मैं एक ही समस्या का सामना करना पड़ा है। यह थोड़ा सा बलपूर्ण बल शैली है, मुझे लगता है, लेकिन बहुत चुस्त है और सभी मामलों के अनुरूप होना चाहिए।

class MyModelAdmin(admin.ModelAdmin): 
    def __init__(self, *args, **kwargs): 
     super(MyModelAdmin, self).__init__(*args, **kwargs) 
     self.inline_instances_hash = {} 
     for inline_class in self.inlines: 
      for inline_instance in self.inline_instances: 
       if isinstance(inline_instance, inline_class): 
        break 
      self.inline_instances_hash[inline_class] = inline_instance 

    def get_inline_instance(self, inline_class): 
     return self.inline_instances_hash[inline_class] 

    def get_form(self, request, obj=None, **kwargs): 
     if obj: 
      self.inline_instances = [] 
      if self.CONDITION: 
       self.inline_instances.append(self.get_inline_instance(
        THE_INLINE_CLASS_I_WANT)) 
      #... 
     else: 
      self.inline_instances = self.inline_instances_hash.values() 
3

मुझे पता है कि यह प्रश्न थोड़ा पुराना है और कोडबेस थोड़ा बदल गया है; अब चीजों को ओवरराइड करने के लिए एक साफ़ बिंदु है: get_inline_instances। आप ऐसा कर सकते हैं:

class MainModelAdmin(models.ModelAdmin): 
    inlines = [RelatedModel1InlineAdmin,RelatedModel2InlineAdmin] 

    def get_inline_instances(self, request, obj=None): 
     #Return no inlines when obj is being created 
     if not obj: 
      return [] 
     unfiltered = super(MainModelAdmin, self).get_inline_instances(request, obj) 
     #filter out the Inlines you don't want 
     if obj.type: 
      return [x for x in unfiltered if isinstance(x,RelatedModel1InlineAdmin)] 
     else: 
      return [x for x in unfiltered if isinstance(x,RelatedModel2InlineAdmin)] 
0

यह मेरे लिए काम किया है, जबकि इस वर्ष पोस्ट में एक ही समस्या का जवाब के लिए खोज। darklow के उत्तर पर विस्तार, मुझे लगता है कि आप आसानी से get_inline_instances को ओवरराइड कर सकते हैं और अपने प्रकार के आधार पर अतिरिक्त चेक जोड़ सकते हैं।

  1. आप में एक बूलियन प्रकार की जांच विधि मॉडल

    वर्ग MainModel (models.Model) जोड़ें:

    name = models.CharField(max_length=50) 
    
    type = models.BooleanField() 
    
    def is_type1(self): 
    
        return type=="some value" 
    
    def is_type2(self): 
        return type=="some value" 
    
  2. प्रकार की जांच पर इनलाइन उदाहरण आधार जोड़े - बस कॉपी और पेस्ट get_inline_insances पेरेंट क्लास से अपने व्यवस्थापक में विधि। मॉडेलएडमिन क्लास और

    क्लास MyModelAdmin (admi) के नीचे दिखाए गए मॉडल प्रकार की जांच करने के लिए ब्लॉक को जोड़ें। n.ModelAdmin):

    inlines = [RelatedModel1, RelatedModel2] 
    
    def get_inline_instances(self, request, obj=None): 
        inline_instances = [] 
        if not obj: 
         return [] 
        for inline_class in self.inlines: 
         inline = inline_class(self.model, self.admin_site) 
         if request: 
          if not (inline.has_add_permission(request) or 
             inline.has_change_permission(request, obj) or 
             inline.has_delete_permission(request, obj)): 
           continue 
          if not inline.has_add_permission(request): 
           inline.max_num = 0 
         if obj.is_type1() and isinstance(inline,RelatedModel1InlineAdmin): 
          inline_instances.append(inline) 
         if obj.is_type2() and isinstance(inline,RelatedModel2InlineAdmin): 
          inline_instances.append(inline) 
    
        return inline_instances 
    
संबंधित मुद्दे