Django无法确定与一对一关系链接一对多的QuerySet



我有一个系统,其中与一个数字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:

  1. 我们使用treat_id而不是treat__id来避免其他加入查询,因为Django已将treat_id保存在PET对象级别上,但是如果您使用treat__id,则可以强制加入查询。
  2. 将属性限制为IDS的迭代器仅是为了可逆性和可维护性。

以下要做的事情应以您的身份:

def find_important_treats(self):
    return Treat.objects.filter(id__in=person.pets.values_list('treat_id'))

它获得了宠物拥有的Treat S的所有ids,然后返回它们。

最新更新