2010-06-27 8 views
7

Sto cercando di capire un modo per visualizzare il seguente RelativeInline solo se Person.is_member è True.In linea condizionale nell'amministratore di Django?

admin.py attuale:

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) 

L'unico suggerimento che ho potuto trovare è che potrei essere in grado di ignorare get_formset, ma non riuscivo a trovare un buon esempio, quindi il mio debole tentativo non ha funzionato

Ecco il mio tentativo fallito:

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) 

ci sono errori generati da questo codice, ma non in linea appare a prescindere dal fatto che Person.is_member è vera o falsa.


Aggiornamento: Un amico mi ha suggerito di provare a cambiare:

inlines = [RelativeInline,] 

a:

self.inlines = [RelativeInline,] 

ma senza alcun risultato. Ho anche provato:

PersonAdmin.inlines = [RelativeInline,] 

ma il risultato è stato lo stesso: nessun errore, nessun inline.

risposta

1

Ho deciso di cambiare l'intero paradigma e di risolvere il mio problema in un modo diverso. Invece di avere un solo amministratore per tutte le persone con una linea condizionale, ho deciso di:

  1. Override il set di query per filtrare per soli soci e mantenere RelativeInline con l'amministratore per questo modello
  2. Creare un modello di delega e sostituisci il suo queryset per filtrare per i non membri. L'amministratore per questo modello non include RelativeInline.

Alla fine, penso che questo sia un approccio più pulito. Ora i membri possono essere mantenuti e i parenti (non membri) possono essere aggiunti in linea. Il NonMemberAdmin consente di modificare i non membri.

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

La soluzione originale era abbastanza vicino. Se guardi in django/contrib/admin/options.py sulla riga 290 vedrai che le classi inline vengono istanziate quando l'amministratore del modello viene istanziato, dopo di che l'elenco inlines viene ignorato. Quindi, l'impostazione successiva dell'elenco in get_formsets() non ha alcun effetto.

Tuttavia, sei corretto che get_formsets() è la cosa da sovrascrivere per rendere i tuoi inline condizionali. Le istanze incorporate sono contenute in self.inline_instances, quindi per disabilitarle in base all'oggetto (ad es.dico che voglio nascondere una linea specifica sul modulo "add") si sarebbe ignorare le cose come:

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

aggiornamento per il 2014 e il Django 1.6: 'per inline in self.get_inline_instances (richiesta, obj):' – imposeren

0

Mi rendo conto che questa domanda è un po 'vecchia e la base di codice è cambiato un po'; c'è un punto di pulizia per ignorare le cose al momento: get_inline_instances. Si può fare questo:

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