通过Through过滤Django Admin中的ManyToMany字段
我的 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号”)参与了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'
的错误。
2 个回答
1
你在 PersonRole
对象上使用 .get_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.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
这个字段。