2010-06-27 16 views
7

Estoy tratando de encontrar una manera de mostrar la siguiente RelativeInline solo si Person.is_member es True.Condicional en línea en Django admin?

admin.py actual:

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) 

La única pista que he podido encontrar es que yo podría ser capaz de anular get_formset, pero no pude encontrar un buen ejemplo, así que mi débil intento no funcionó

Aquí está mi intento fallido:

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) 

No hay errores generados por este código, pero no aparece ninguna línea, independientemente de si es o no Person.is_member es verdadera o falsa.


Actualización: Un amigo me sugirió que probar cambiando:

inlines = [RelativeInline,] 

a:

self.inlines = [RelativeInline,] 

pero fue en vano. También probé:

PersonAdmin.inlines = [RelativeInline,] 

pero el resultado fue el mismo - sin error, sin línea.

Respuesta

1

Decidí cambiar todo el paradigma y resolver mi problema de otra manera. En lugar de tener un solo administrador para todas las personas con una línea condicional, decidí:

  1. Sustituir el conjunto de consultas para filtrar sólo para miembros y mantener RelativeInline con el administrador de este modelo
  2. Crear un modelo de poder y anula su queryset para filtrar para los no miembros. El administrador de este modelo no incluye RelativeInline.

Al final, creo que este es un enfoque más limpio. Ahora los Miembros pueden mantenerse y los familiares (no miembros) pueden agregarse en línea. NonMemberAdmin permite la edición de no miembros.

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

Su solución original estaba bastante cerca. Si mira en django/contrib/admin/options.py alrededor de la línea 290, verá que las clases en línea se instancian cuando se crea una instancia del administrador del modelo, después de lo cual se ignora la lista inlines. Por lo tanto, establecer esta lista más adelante en get_formsets() no tiene ningún efecto.

Sin embargo, tiene razón en que get_formsets() es lo que debe sobrescribir para hacer que sus líneas sean condicionales. Las instancias en línea están contenidas en self.inline_instances, por lo tanto, deshabilitarlas en función del objeto (p.digo que quiero ocultar una línea específica en el formulario de "añadir") que le anular se siente:

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

actualización para 2014 y Django 1.6: ' de línea en self.get_inline_instances (solicitud, obj):' – imposeren

0

realizo esta pregunta es un poco viejo y el código base se ha cambiado un poco; hay un punto más limpio para anular las cosas ahora: get_inline_instances. Usted puede hacer esto:

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