Django Admin - 通过模型过滤 ManyToManyField

Django Admin - Filter ManyToManyField with through model

如何在与手动定义的 through 模型具有 ManyToManyField 关系的对象的管理页面中过滤查询集?

给定 models.py

class Foo(models.Model):
    foo_field1 = models.CharField(max_length=50)

class Main(models.Model):
    main_field1 = models.CharField(max_length=50)
    m2mfield = models.ManyToManyField(Foo, through="FooBar")

class FooBar(models.Model):
    main = models.ForeignKey(Main, on_delete=models.CASCADE)
    foo = models.ForeignKey(Foo, on_delete=models.CASCADE)
    new_field = models.CharField(max_length=50)

里面admin.py

class M2MInlineAdmin(admin.TabularInline):
    model = Main.m2mfield.through
    extra = 1

class MainAdmin(admin.ModelAdmin):
   inlines = [M2MInlineAdmin,]
   ...

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        print('called formfield_for_manytomany')
        return super().formfield_for_manytomany(db_field, request, **kwargs)

    def get_field_queryset(self, db, db_field, request):
        print('called get_field_queryset')
        return super().get_field_queryset(db, db_field, request)

我尝试访问这两种方法,但是如果我指定 through table,其中的 none 会被调用。但是,如果 ManyToMany 关系简单地定义如下,它们就会被调用:

class Main(models.Model):
    main_field1 = models.CharField(max_length=50)
    m2mfield = models.ManyToManyField(Foo)

当指定了 table(同时能够访问 request 上下文)时,是否有过滤查询集的方法?

编辑:

当 ManyToManyField 指定了 through 模型时确实会调用这些方法,只有在 modelAdmin class.[=21 中没有指定 fieldsets 时才会调用这些方法=]

如何在定义 fieldsets 时访问这些方法?

您可以在内联 class 上使用 formfield_for_foreignkey() 方法。

class M2MInlineAdmin(admin.TabularInline):
    model = Main.m2mfield.through
    extra = 1

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

formfield_for_manytomany 方法 seems to be called 仅当使用默认形式时。定义字段集时,它使用不同的形式,这就是为什么没有调用上述方法的原因。

由于您对多对多字段使用表格管理,您可以覆盖 get_queryset 以使用字段进行过滤。

class M2MInlineAdmin(admin.TabularInline):
    model = Main.fruits.through
    extra = 1

    def get_queryset(self, request):
        qs = super(M2MInlineAdmin, self).get_queryset(request)
        qs = qs.filter(some_arg=some_value)
        return qs

或者,您可以编写自定义模型表单并在管理中使用它而不是默认表单。

class MainAdminForm(forms.ModelForm):

    class Meta:
        model = Main
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # custom setup


class MainAdmin(admin.ModelAdmin):
    form = MainAdminForm