【问题标题】:filter foreignkey field in django admin在 django admin 中过滤外键字段
【发布时间】:2012-04-28 01:52:46
【问题描述】:

我有这些模型:

class Entity(models.Model):
       name=models.CharField(max_length=100)
      
class Theme(models.Model):
   name=models.CharField(max_length=100)
   entity=models.OneToOneField(Entity)

class Company(models.Model):
    name=models.CharField(max_length=100)
    theme=models.OneToOneField(Theme,null=True,blank=True)

我想在管理员中添加Company 时过滤theme 字段,如下所示:

class CompanyAdmin(admin.ModelAdmin):
   def queryset(self, request):
      qs = super(CompanyAdmin, self).queryset(request)
      qs.theme.queryset = Theme.objects.filter(name__iexact='company')
      return qs
      
admin.site.register(Company, CompanyAdmin)

我尝试了很多东西,但没有任何效果!我该怎么做?

【问题讨论】:

  • 查看this question的答案
  • formfield_for_foreignkey-example in the documentation 准确描述了如何执行此操作(在ModelAdmin 方面)。扩展 formfield_for_foreignkey() 也适用于 OneToOneField

标签: python django


【解决方案1】:

我实际上更喜欢在get_form 中这样做:

姜戈

class CompanyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(CompanyAdmin, self).get_form(request, obj, **kwargs)
        form.fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
        return form

Django >= 2

class CompanyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(CompanyAdmin, self).get_form(request, obj, **kwargs)
        form.base_fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
        return form

【讨论】:

  • 这个方法比公认的要好,因为它允许访问obj。
  • 在 Django 2 中,您需要调用 form.base_fields 而不是 form.fields 来获取属性。
  • 如果您能详细说明使用get_formrender_change_form 之间的区别,那就太好了。
  • 我得到类型对象 '...Form' 没有属性 'fields
【解决方案2】:

有点不相关,但和这个类似,所以我会在这里发布。

我正在寻找一种方法来删除 ModelForm 外键字段上的 NULL 选项选择。我首先认为我可以像在此处的其他答案中那样过滤查询集,但这不起作用。

我发现我可以在get_form方法中像这样过滤pk值为NULL的条目:


class CompanyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        # remove null choice
        form.base_fields["theme"].choices = ((pk, display) for pk, display in form.base_fields["theme"].choices if pk)
        return form

【讨论】:

    【解决方案3】:

    在 Django 3 中很容易:

    class CompanyAdmin(admin.ModelAdmin):
        list_display = ('name','theme')
        list_filter = ('theme__name',)
    
    admin.site.register(Company,CompanyAdmin)
    

    这将在屏幕右侧显示一个过滤器,其中包含您的主题名称列表。

    【讨论】:

    • 这不能回答问题。从 Django 的最早版本开始,ModelAdmins 就可以使用列表过滤器
    【解决方案4】:

    我面临需要将过滤器添加到父 ModelAdmin 类(所有其他 ModelAdmins 继承自)的 foreignKey 查询集,也就是说,我无法确切知道我需要哪个模型,这是我的解决方案:@987654321 @

    class TSModelAdmin(admin.ModelAdmin):
       exclude = ('site',)
        ...
    
          def formfield_for_foreignkey(self, db_field, request, **kwargs):
            if db_field.related_model:
                kwargs["queryset"] = 
                db_field.related_model.objects.filter(site=request.user.user_profile.site)
            return super().formfield_for_foreignkey(db_field, request, **kwargs)
    

    使用的django版本2.2.10

    【讨论】:

      【解决方案5】:

      看这里http://books.agiliq.com/projects/django-admin-cookbook/en/latest/filter_fk_dropdown.html

      @admin.register(Hero)
      class HeroAdmin(admin.ModelAdmin, ExportCsvMixin):
          ...
          def formfield_for_foreignkey(self, db_field, request, **kwargs):
              if db_field.name == "category":
                  kwargs["queryset"] = Category.objects.filter(name__in=['God', 'Demi God'])
              return super().formfield_for_foreignkey(db_field, request, **kwargs)
      
      【解决方案6】:

      使用render_change_form 方法:

      class CompanyAdmin(admin.ModelAdmin):
          def render_change_form(self, request, context, *args, **kwargs):
               context['adminform'].form.fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
               return super(CompanyAdmin, self).render_change_form(request, context, *args, **kwargs)
      

      【讨论】:

      • 把最后一行改成return super(CompanyAdmin, self).render_change_form(request, context, *args, **kwargs)
      【解决方案7】:

      另一种选择是创建自定义模型表单,其中 theme 字段的查询集属性将被微调以满足您的需求。

      class CompanyForm(ModelForm):
          class Meta:
              model = CompanyForm
              fields = __all__ # or a tuple of fields
      
          def __init__(self, *args, **kwargs):
              super(CompanyForm, self).__init__(*args, **kwargs)
              if self.instance: # Editing and existing instance
                  self.fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
      

      这个模型表单也可以在 django 管理区域之外重复使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-14
        • 2019-02-17
        • 2014-08-24
        • 1970-01-01
        • 1970-01-01
        • 2018-12-13
        • 2017-01-31
        • 1970-01-01
        相关资源
        最近更新 更多