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

时间:2017-12-14 00:55:12

标签: python django python-3.x django-models django-queryset

我有一个系统,其中有一个与一个模型的数量有多对一的关系(比如1a - >多个b),并且许多模型与另一个模型具有一对一的关系(比如说1b - > 1 c)。如此画出:

  /--- b1 --- c1
 /
a ---- b2 --- c2
 \
  \--- b3 --- c3

我决定创建一个方法,收集与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

2 个答案:

答案 0 :(得分: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)
  • 不使用缓存:
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)

注意:

  1. 我们使用treat_id代替treat__id来避免其他联接查询,因为django已经将treat_id保存在Pet对象级别,但是如果您使用treat__id那么就强迫加入查询。
  2. 将属性限制为ID的迭代器仅用于可逆性和可维护性

答案 1 :(得分:2)

以下内容应该符合您的要求:

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

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