Django管理员有条件内联?

时间:2010-06-27 01:48:24

标签: django django-admin conditional inline

我正试图找出一种只有在Person.is_member为True时才显示以下RelativeInline的方法。

目前的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)

我能找到的唯一提示是我可以覆盖get_formset,但我找不到一个好的例子,所以我的微弱尝试不起作用。

这是我失败的尝试:

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)

此代码不会生成任何错误,但无论Person.is_member是True还是False,都不会显示内联。


更新: 一位朋友建议我尝试改变:

inlines = [RelativeInline,]

为:

self.inlines = [RelativeInline,]

但无济于事。我也尝试过:

PersonAdmin.inlines = [RelativeInline,]

但结果是一样的 - 没有错误,没有内联。

3 个答案:

答案 0 :(得分:3)

你原来的解决方案非常接近。如果查看第290行的django / contrib / admin / options.py,您将看到在实例化模型管理员时实例化内联类,之后忽略inlines列表。因此,稍后在get_formsets()中设置此列表无效。

但是,你是正确的,get_formsets()是要覆盖的东西,以使你的内联成为条件。内联实例包含在self.inline_instances中,因此要根据对象禁用它们(例如,我想隐藏“添加”表单上的特定内联),您可以覆盖它:

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 :(得分:1)

我决定改变整个范式并以不同的方式解决我的问题。我没有为具有条件内联的所有人设置单一管理员,而是决定:

  1. 覆盖查询集以过滤仅限成员,并将RelativeInline与此模型的管理员保持一致
  2. 创建代理模型并覆盖其查询集以过滤非成员。此模型的管理员不包括RelativeInline。
  3. 最后,我认为这是一种更清洁的方法。现在可以维护成员,并且可以在内联中添加亲属(非成员)。 NonMemberAdmin允许编辑非成员。

    <强> 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)
    

答案 2 :(得分:0)

我意识到这个问题有点陈旧,而且代码库有所改变;现在有一个更清晰的要点覆盖事物:get_inline_instances。你可以这样做:

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