Django 无法确定使用一对一关系链接一对多的查询集
Posted
技术标签:
【中文标题】Django 无法确定使用一对一关系链接一对多的查询集【英文标题】:Django cannot determine queryset for chaining one-to-many with one-to-one relationship 【发布时间】:2018-05-28 00:18:25 【问题描述】:我有一个系统,其中与数字 a 模型(例如 1 a -> many b)存在多对一关系,并且许多模型与另一个模型(例如 1 b -> 1 c)存在一对一关系)。画成这样:
/--- b1 --- c1
/
a ---- b2 --- c2
\
\--- b3 --- c3
我决定创建一个方法来收集与a
对应的所有c
。
给定一个与我的结构相同的模型系统,我能想到的最好的方法如下所示:Person.find_important_treats()
。
有没有更好的方法不涉及对数据库的这么多调用?
from django.db import models
class Person(models.Model):
""" The 'a' from my above example """
def find_important_treats(self):
return (pet.treat for pet in self.pets)
class Pet(models.Model):
""" The 'b' from my above example """
owner = models.ForeignKey(
to=Person,
related_name='pets'
)
favourite_treat = models.ForeignKey(
to=Treat,
)
class Treat(models.Model):
""" The 'c' from my above example """
pass
【问题讨论】:
可能会沿着这些思路找到答案Treat.objects.filter(pet__owner__pk = personId)
。
您能否更具体一点,您是对整个点心对象感兴趣还是只对点心 ID 感兴趣?它有很大的不同!
@DhiaTN,我想要整个款待(贪婪的我),因为它有我想在我的模板中呈现的信息。
【参考方案1】:
以下应该做你所追求的:
def find_important_treats(self):
return Treat.objects.filter(id__in=person.pets.values_list('treat_id'))
获取宠物拥有的Treat
s中的所有ids
,然后返回。
【讨论】:
【参考方案2】:根据您的用例,我建议两个几乎相似的解决方案:
使用缓存 class Person(models.Model):
""" The 'a' from my above example """
@property
def iter_important_treats(self):
return (pet.treat_id for pet in self.pets.all()) # will use the cached objects if they exist
person = Person.objects.get(id=person_id).select_related('pets') # to cache the pets list within the person object avoiding future additional queries
treats = Treat.objects.filter(id__in=person.iter_importent_treats)
不使用缓存:
class Person(models.Model):
""" The 'a' from my above example """
@property
def iter_important_treats(self):
return iter(self.pets.values_list('treat_id', flat=True)) # caching will not affect the query behviour
person = Person.objects.get(id=person_id)
treats = Treat.objects.filter(id__in=person.iter_importent_treats)
注意:
-
我们使用
treat_id
而不是treat__id
来避免额外的连接查询,因为django 已经在Pet 对象级别保存了treat_id
,但是如果您使用treat__id
,那么您将强制进行连接查询。
将属性限制为 ID 的迭代器只是为了实现可逆性和可维护性
【讨论】:
以上是关于Django 无法确定使用一对一关系链接一对多的查询集的主要内容,如果未能解决你的问题,请参考以下文章