在Django admin中有条件内联?

我试图找出一种方式来显示下面的RelativeInline只有当Person.is_member是真实的。

当前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)

此代码不会生成错误,但不管内部是否为真或假,都不会出现内联。


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

inlines = [RelativeInline,]

至:

self.inlines = [RelativeInline,]

但无济于事。 我也试过:

PersonAdmin.inlines = [RelativeInline,]

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


你的原始解决方案非常接近。 如果你看看290行左右的django / contrib / admin / options.py,你会发现内联类在实例化模型admin时被实例化,之后内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)

我决定改变整个范式,用另一种方式解决我的问题。 对于所有使用条件内联的人员,我决定不要使用单个管理员:

  • 重写查询集以过滤仅限会员,并使该模型的管理员保持RelativeInline
  • 创建代理模型并覆盖其查询集以筛选非成员。 此模型的管理员不包含RelativeInline。
  • 最后,我认为这是一个更清洁的方法。 现在可以维护成员,并且可以在内联中添加亲属(非成员)。 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)
    

    我意识到这个问题有点老,代码库已经改变了一点; 现在有一个更清晰的要点: 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
    
    链接地址: http://www.djcxy.com/p/46629.html

    上一篇: Conditional inline in Django admin?

    下一篇: How to do QObject::moveToThread() when using QThreadPool?