【问题标题】:Conditional inline in Django admin?Django admin中的条件内联?
【发布时间】:2011-03-08 18:05:08
【问题描述】:

我试图找出一种仅在 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,]

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

【问题讨论】:

    标签: django django-admin conditional inline


    【解决方案1】:

    我决定改变整个范式并以不同的方式解决我的问题。我决定:

    1. 覆盖查询集以过滤仅限成员,并将 RelativeInline 与该模型的管理员保持一致
    2. 创建代理模型并覆盖其查询集以过滤非成员。此模型的管理员不包括 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)
    

    【讨论】:

      【解决方案2】:

      您最初的解决方案非常接近。如果您在 django/contrib/admin/options.py 的第 290 行附近查看,您会看到内联类在模型管理员被实例化时被实例化,之后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)
      

      【讨论】:

      • 2014 和 django 1.6 的更新:for inline in self.get_inline_instances(request, obj):
      【解决方案3】:

      我意识到这个问题有点老了,代码库也发生了一些变化;现在有一个更清晰的点可以覆盖事物: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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-23
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 2023-03-20
        • 2020-04-16
        • 2011-08-09
        • 2013-03-17
        相关资源
        最近更新 更多