django admin - 在具有中间表的多对多字段中使用过滤器水平

时间:2015-10-20 14:20:47

标签: django django-admin

是否可以将filter_horizontal用于具有中间表的ManyToManyField字段,例如没有中间表的字段?

e.g:

class A(models.Model):
    f1 = models.ManyToManyField(B)
    f2 = models.ManyToManyField(C, through='T')

class B(models.Model):
    pass

class C(models.Model):
    pass

class T(models.Model):
    a = models.ForeignKey(A)
    c = models.ForeignKey(C)

class AAdmin(admin.ModelAdmin):
    filter_horizontal = ('f1', 'f2', )

2 个答案:

答案 0 :(得分:1)

如果您有多个具有中间表的字段,则无法显示常规,过滤器水平或过滤器垂直窗口小部件。原因是中间表可能具有无法在这些小部件中显示的额外字段。

可以将相关模型显示为内联。有关详细信息,请参阅working with many-to-many intermediary models上的文档。

答案 1 :(得分:0)

窗口小部件的名称为 FilteredSelectMultiple ,您必须在管理视图中覆盖 formfield_for_manytomany 方法。这是我用过的。 我有一个公司模型,其中有许多课程,而会员是中间模型。

class Company(models.Model):
    courses = models.ManyToManyField('courses.Course', through='Member', related_name='companies')

class Member(models.Model):
    user = models.OneToOneField(get_user_model(),
    related_name="%(app_label)s_%(class)s",
    on_delete=models.CASCADE,
)
organization = TenantForeignKey(
    Company, related_name="organization_users", on_delete=models.CASCADE)

这是我的管理员视图

class CompanyAdmin(admin.ModelAdmin):
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        db = kwargs.get('using')

        if db_field.name == 'courses':
            kwargs['widget'] = FilteredSelectMultiple(
                db_field.verbose_name, is_stacked=False
            )
        else:
            return super().formfield_for_manytomany(db_field, request, **kwargs)
        if 'queryset' not in kwargs:
            queryset = Course.objects.filter(is_active=True)
            if queryset is not None:
                kwargs['queryset'] = queryset
        form_field = db_field.formfield(**kwargs)
        msg = 'Hold down “Control”, or “Command” on a Mac, to select more than one.'
        help_text = form_field.help_text
        form_field.help_text = (
            format_lazy('{} {}', help_text, msg) if help_text else msg
        )
        return form_field