我有一个系统,其中与一个数字A模型有很多一到一的关系(例如1 A->许多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
我建议两个几乎相似的解决方案,具体取决于您的用例:
- 使用缓存
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)
nb:
- 我们使用
treat_id
而不是treat__id
来避免其他加入查询,因为Django已将treat_id
保存在PET对象级别上,但是如果您使用treat__id
,则可以强制加入查询。 - 将属性限制为IDS的迭代器仅是为了可逆性和可维护性。
以下要做的事情应以您的身份:
def find_important_treats(self):
return Treat.objects.filter(id__in=person.pets.values_list('treat_id'))
它获得了宠物拥有的Treat
S的所有ids
,然后返回它们。