如何减少django模型中的查询
以下是两个示例Django模型。 要特别注意has_pet方法。
class Person(models.Model):
name = models.CharField(max_length=255)
def has_pet(self):
return bool(self.pets.all().only('id'))
class Pet(models.Model):
name = models.CharField(max_length=255)
owner = models.ForeignKey(Person, blank=True, null=True, related_name="pets")
这里的问题是has_pet方法总是生成一个查询。 如果你做这样的事情。
p = Person.objects.get(id=1)
if p.has_pet():
...
然后,你实际上会做一个额外的查询来检查一个人是否有宠物。 如果你必须检查多个人,这是一个大问题。 如果在像这样的模板中使用,它也会生成查询。
{% for person in persons %}
{% if person.has_pet %}
{{ person.name }} owns a pet
{% else %}
{{ person.name }} is petless
{% endif %}
{% endfor %}
这个示例在渲染模板时将实际为查询集中的每个人员执行额外的查询。
有没有办法只用一个查询来做到这一点,或者每个人至少做一个额外的查询? 也许有另一种方法来设计这个来完全避免这个问题。
我想为Person添加一个BooleanField,并且在宠物被保存或删除时更新该字段。 这真的是正确的路吗?
另外,我已经正确设置了memcached,所以只有在结果尚未被缓存的情况下才会发生这些查询。 我正在寻求移除查询,以获得更大的优化。
如果你想要一个所有有宠物的人的列表,你可以在一个查询中做到这一点:
Person.objects.exclude(pets=None)
听起来你想要遍历一个单一的人名单,使用注释可能是有道理的:
for person in Person.objects.annotate(has_pet=Count('pets')):
if person.has_pet: # if has_pet is > 0 this is True, no extra query
如果Django有一个Exists
聚合,但它不会,我不知道添加一个会有多困难。 你当然应该配置文件,并找出这是否适合你。
就我个人而言,我可能只是将has_pets
作为布尔值存储在模型上,这可能是最有效的方法。