Django无法确定以一对一关系链接一对多的查询集

Ste*_*ier 5 python django django-models django-queryset python-3.x

我有一个系统,其中存在多个与一个模型的关系(比如说a 1 - >很多b),并且许多模型与另一个模型具有一对一的关系(比如说1b - > 1 c).如此绘制:

  /--- b1 --- c1
 /
a ---- b2 --- c2
 \
  \--- b3 --- c3
Run Code Online (Sandbox Code Playgroud)

我决定创建一个方法,收集所有c对应的方法a.

给定一个与我的结构相同的模型系统,我能想出的最好的方法显示在方法中: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
Run Code Online (Sandbox Code Playgroud)

Dhi*_*aTN 4

我根据您的用例建议两个几乎相似的解决方案:

  • 使用缓存
    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)
Run Code Online (Sandbox Code Playgroud)
  • 不使用缓存:
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)
Run Code Online (Sandbox Code Playgroud)

注意:

  1. 我们使用它treat_idtreat__id避免额外的连接查询,因为 django 已经treat_id在 Pet 对象级别保存了,但是如果您使用treat__id,那么您会强制执行连接查询。
  2. 将属性限制为 ID 迭代器只是为了可逆性和可维护性