在Admin中通过模型显示过滤后的ManyToMany结果
这是我的 models.py 文件:
class Person(models.Model):
surname = models.CharField(max_length=100, blank=True, null=True)
forename = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return '{}, {}'.format(self.surname, self.forename)
class PersonRole(models.Model):
ROLE_CHOICES = [
("Principal investigator", "Principal investigator"),
[etc...]
]
title = models.CharField(choices=TITLE_CHOICES, max_length=9)
project = models.ForeignKey('Project', on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
person_role = models.CharField(choices=ROLE_CHOICES, max_length=30)
def __str__(self):
return '{}: {} as {}.'.format(self.project, self.person, self.person_role)
class Project(models.Model):
title = models.CharField(max_length=200)
person = models.ManyToManyField(Person, through=PersonRole)
def __str__(self):
return self.title
def get_PI(self, obj):
return [p.person for p in self.person.all()] #I'll then need to filter where person_role is 'Principal investigator', which should be the easy bit.
在我的后台管理系统中,我想在主表中显示一个人(主要研究者):
class ProjectAdmin(ImportExportModelAdmin):
list_filter = [PersonFilter, FunderFilter]
list_display = ("title", "get_PI")
ordering = ('title',)
我想要的效果是:在后台的项目表中显示角色为“主要研究者”的人。
你可以看到我在我的 models.py
中创建了一个 get_PI()
方法,并在 list_display
中引用了它。但是我遇到了一个问题,提示 Project.get_PI() 缺少一个必需的位置参数:'obj'
。我哪里做错了呢?
1 个回答
2
去掉 obj
这个参数:
class Project(models.Model):
title = models.CharField(max_length=200)
person = models.ManyToManyField(Person, through=PersonRole)
def __str__(self):
return self.title
def get_PI(self): # 🖘 no obj
return [p.person for p in self.person.all()]
不过这样会引入一个叫做 N+1 问题,所以你可能需要提高效率,可以使用:
class ProjectAdmin(ImportExportModelAdmin):
list_filter = [PersonFilter, FunderFilter]
list_display = ('title', 'get_PI')
ordering = ('title',)
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related('person')
至于过滤,你可以使用:
class Project(models.Model):
def get_PI(self):
return [
p
for p in self.person.filter(
personrole__title__contains='Principal investigator'
)
]
不过这样会再次降低查询速度,因为现在我们对每一条记录都要进行一次查询。