2010-06-27 26 views
7

Próbuję znaleźć sposób, aby wyświetlić następujące RelativeInline tylko jeśli Person.is_member jest True.Warunkowo wbudowane w admin Django?

Aktualny admin.py:

class RelativeInline(admin.TabularInline): 
    model = Relative 
    fk_name = 'member' 

class PersonAdmin(admin.ModelAdmin): 
    inlines = [RelativeInline,] 
    ordering = ('first_name',) 
    list_filter = ('is_member',) 
    search_fields = ('first_name', 'last_name',) 
    date_hierarchy = 'member_date' 
    list_display = ('first_name', 'last_name', 'is_member', 'member_date', 'photo') 

admin.site.register(Person, PersonAdmin) 

Jedyną wskazówką udało mi się znaleźć jest to, że mogę być w stanie przesłonić get_formset, ale nie mogłem znaleźć dobry przykład, więc moja słaba próba nie działa.

Oto moja nieudana próba:

class RelativeInline(admin.TabularInline): 
    model = Relative 
    fk_name = 'member' 

class PersonAdmin(admin.ModelAdmin): 
    ordering = ('first_name',) 
    list_filter = ('is_member',) 
    search_fields = ('first_name', 'last_name',) 
    date_hierarchy = 'member_date' 
    list_display = ('first_name', 'last_name', 'is_member', 'member_date', 'photo') 

    def get_formset(self, request, obj=None, **kwargs): 
     if obj.is_member: 
      inlines = [RelativeInline,] 
     return super(PersonAdmin, self).get_formset(request, obj, **kwargs) 

admin.site.register(Person, PersonAdmin) 

Brak błędów generowanych przez ten kod, ale nie inline pojawia się niezależnie od tego, czy Person.is_member prawdziwe czy fałszywe.


Aktualizacja: Przyjaciel zaproponował mi spróbować zmienić:

inlines = [RelativeInline,] 

do:

self.inlines = [RelativeInline,] 

ale bezskutecznie. Próbowałem również:

PersonAdmin.inlines = [RelativeInline,] 

, ale wynik był taki sam - brak błędu, brak linii.

Odpowiedz

1

Postanowiłem zmienić cały paradygmat i rozwiązać mój problem w inny sposób. Zamiast jednego administratora dla wszystkich osób z warunkowego inline, postanowiłem:

  1. przesłonić queryset filtrowania dla członków tylko i zachować RelativeInline z administratorem tego modelu
  2. Tworzenie modelu proxy i przesłonięcie swojego zestawu zapytań w celu filtrowania dla osób niebędących członkami. Administrator tego modelu nie zawiera RelativeInline.

Podsumowując, uważam, że jest to czystsze podejście. Teraz członkowie mogą być obsługiwani, a krewni (nie będący członkami) mogą być dodani w linii. NonMemberAdmin pozwala na edycję nie-członków.

models.py:

class Person(models.Model): 
    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50) 
    is_member = models.BooleanField() 
    is_active = models.BooleanField(default=True) 

    class Meta: 
     verbose_name_plural = 'Members' 
     ordering = ('first_name', 'last_name') 

class PersonProxy(Person): 
    class Meta: 
     proxy = True 
     verbose_name_plural = 'Non-Members' 

class Relationship(models.Model): 
    name = models.CharField(max_length=50) 

class Relative(models.Model): 
    member = models.ForeignKey(Person, related_name='relative_member') 
    relative = models.ForeignKey(Person, related_name='relative_relative') 
    relationship = models.ForeignKey(Relationship) 

admin.py:

class RelativeInline(admin.TabularInline): 
    model = Relative 
    fk_name = 'member' 


class MemberAdmin(admin.ModelAdmin): 
    inlines = [RelativeInline,] 
    ordering = ('first_name',) 
    # list_filter = ('is_member',) 
    search_fields = ('first_name', 'last_name',) 
    # date_hierarchy = 'member_date' 
    list_display = ('first_name', 'last_name', 'member_date') 

    def queryset(self, request): 
     return (super(MemberAdmin, self).queryset(request) 
       .filter(is_member=True, is_active=True)) 


class NonMemberAdmin(admin.ModelAdmin): 
    ordering = ('first_name',) 
    search_fields = ('first_name', 'last_name',) 
    list_display = ('first_name', 'last_name') 

    def queryset(self, request): 
     return (super(NonMemberAdmin, self).queryset(request) 
       .filter(is_member=False, is_active=True)) 


admin.site.register(Person, MemberAdmin) 
admin.site.register(PersonProxy, NonMemberAdmin) 
3

Oryginalne rozwiązanie było całkiem blisko. Jeśli spojrzysz w django/contrib/admin/options.py wokół linii 290 zobaczysz, że wbudowane klasy są tworzone, gdy administrator modelu jest instancjonowany, po czym lista inlines jest ignorowana. Więc ustawienie tej listy później w get_formsets() nie ma żadnego efektu.

Jednak masz rację, że get_formsets() jest czymś, co należy przesłonić, aby uwarunkować inline. Inline instances są zawarte w self.inline_instances, więc aby wyłączyć je na podstawie obiektu (np.powiedzieć, że chcą ukryć konkretną inline „Dodaj” formie) chcesz zastąpić go lubię:

class MyAdmin(models.ModelAdmin): 

    inlines = [MyInline, SomeOtherInline] 

    def get_formsets(self, request, obj=None): 
     for inline in self.inline_instances: 
      if isinstance(inline, MyInline) and obj is None: 
       continue 
      yield inline.get_formset(request, obj) 
+1

aktualizacja na rok 2014 i django 1.6: 'inline w self.get_inline_instances (wniosek, obj):' – imposeren

0

uświadamiam sobie to pytanie jest trochę stary i kodzie zmienił się nieco; istnieje teraz czystszy punkt do przesłonięcia rzeczy: get_inline_instances. Można to zrobić:

class PersonAdmin(models.ModelAdmin): 

inlines = [RelativeInline,] 

def get_inline_instances(self, request, obj=None): 
    to_return = super(MyAdmin, self).get_inline_instances(request, obj) 
    #filter out the RelativeInlines if obj.is_member is false 
    if not obj or not obj.is_member: 
     to_return = [x for x in to_return if not isinstance(x,RelativeInline)] 
    return to_return