在 Django Admin 中通过 ManyToMany 字段使用 Through

问题描述 投票:0回答:2

我的

models.py

class Subject(models.Model):
    name = models.CharField(max_length=200)

class Person(models.Model):
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
    school = models.ForeignKey(School, on_delete=models.CASCADE, blank=True, null=True)

class PersonRole(models.Model):
    project = models.ForeignKey('Project', on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)

class Project(models.Model):

    title = models.CharField(max_length=200)
    person = models.ManyToManyField(Person, through=PersonRole)

现在,在我的管理后端中,我想使用

list_filter
添加一个不错的过滤。此过滤器应该可以按学校过滤某人所属的项目。换句话说,如果约翰(属于“1 号”学校)附属于 1 号项目。 3,我希望后端的项目表只显示项目号。 3. 我想我应该定制一个simplelistfilter。不过,首先,我对如何获取项目附属人员的学校列表有点困惑。

到目前为止我的尝试是:

class PersonRole(models.Model):

    [...]

    def get_school(self):
        return self.person.school


class Project(models.Model):

    @admin.display(description='PI School')
    def get_PI_school(self):
        return [p for p in self.person.get_school()] 

admin.py

class ProjectAdmin(admin.ModelAdmin):
    list_display = ("get_PI_school",) #This is just to see if the field is populated

有了这个,我得到了

'ManyRelatedManager' object has no attribute 'get_school'

python django django-models
2个回答
1
投票

您在

.get_school()
对象上使用
PersonRole

class Project(models.Model):
    @admin.display(description='PI School')
    def get_PI_school(self):
        return [p.get_school() for p in self.personrole_set.all()]

我们可以通过在同一查询中获取相关的

Person
School
来提高效率:

class Project(models.Model):
    @admin.display(description='PI School')
    def get_PI_school(self):
        return [
            p.get_school()
            for p in self.personrole_set.select_related('person__school')
        ]

您可以使用以下方式筛选 PI 角色:

class Project(models.Model):
    @admin.display(description='PI School')
    def get_PI_school(self):
        return [
            p.get_school()
            for p in self.personrole_set.filter(
                title__contains="Principal investigator"
            )
        ]

当然,您的

PersonRole
模型仍然具有
title
字段。


0
投票

在尝试了不同的选项后,我设法使用

SimpleListFilter
来做到这一点,而且比我想象的要容易!我什至不需要在
properties
中定义
models.py
等。这是代码,进入
admin.py
:

class PISchoolFilter(admin.SimpleListFilter):

   title = 'PI School'
   parameter_name = 'school'

   def lookups(self, request, model_admin):
        return (
                ('Arts & Humanities Admin',('Arts & Humanities Admin')),
    [...]
                )

   def queryset(self, request, queryset):
    if self.value() == 'Arts & Humanities Admin':
        return queryset.filter(
            person__personrole__person_role__contains="Principal investigator",
            person__personrole__person__school=5
        ).distinct()
    [...]
© www.soinside.com 2019 - 2024. All rights reserved.