问题描述
我有一个使用 MysqL 的 PHP/html 数据库,正在将其转移到 Django 项目中。
我拥有所有功能,但由于与其他表的关系,加载我想要的数据表非常缓慢。
搜索几天后,我知道我可能必须使用 model.Manager
才能使用 prefetch_all
。但是,我并没有被困在如何将其调用到我的模板中。
我有以下模型(简化版):
class OrganisationManager(models.Manager):
def get_queryset_director(self):
person_query = Position.objects.select_related('person').filter(position_current=True,position_type="director"
)
return super().get_queryset().prefetch_related(Prefetch('position_set',queryset=person_query,to_attr="position_list"))
def get_queryset_president(self):
person_query = Position.objects.select_related('person').filter(position_current=True,position_type="president"
)
return super().get_queryset().prefetch_related(Prefetch('position_set',to_attr="position_list"))
class Person(models.Model):
full_name = models.CharField(max_length=255,blank=True,null=True)
country = models.ForeignKey(Country,models.CASCADE,null=True)
birth_date = models.DateField(blank=True,null=True)
class Organisation(models.Model):
organisation_name = models.CharField(max_length=255,null=True)
positions = models.ManyToManyField(Person,through='Position')
# positions are dynamic,even though there should only be only one director and president at each given time,a onetoone model wouldn't work in this scenario
objects = OrganisationManager()
# The following defs are currently used to show the names and start dates of the director and president in the detailview and listview
def director(self):
return self.position_set.filter(position_current=True,position_type="director").last()
def president(self):
return self.position_set.filter(position_current=True,position_type="P").last()
class Position(models.Model):
POSITION_TYPES = (
('president','President'),('director','Director'),)
person = models.ForeignKey(Person,on_delete=models.CASCADE)
organisation = models.ForeignKey(Organisation,on_delete=models.CASCADE)
position_type = models.CharField(max_length=255,choices=POSITION_TYPES,null=True)
position_current = models.BooleanField(default=False)
position_start = models.CharField(max_length=10,null=True)
我希望我的桌子看起来像这样:
组织名称 | 总裁 | 总裁上任日期 | 导演 | 导演开始日期 |
---|---|---|---|---|
组织 1 | 组织 1 的主席 | 2013 | 组织 1 总监 | 2015 |
组织 2 | 组织 2 主席 | 2018 | 组织 2 总监 | 2017 |
使用我目前拥有的代码,一切都很好。但是因为每次都要调用数据库,这甚至会导致Heroku超时。
我不明白如何在表 (models.Manager
) 模板中的 ListView
中使用预取查询。谢谢!
解决方法
实现您想要的结果的一种方法是使用 subqueries。所以像:
president_subquery = Position.objects.filter(
organisation=OuterRef('pk'),position_type='president',position_current=True
).last()
director_subquery = Position.objects.filter(
organisation=OuterRef('pk'),position_type='director',position_current=True
).last()
Organisation.objects.annotate(
president=Subquery(president_subquery.values('person__fullname')),president_start_date=Subquery(president_subquery.values('position_start')),director=Subquery(director_subquery.values('person__fullname')),director_start_date=Subquery(director_subquery.values('position_start')),)