假设我有以下型号:
class Invoice(models.Model):
...
class Note(models.Model):
invoice = models.ForeignKey(Invoice, related_name='notes', on_delete=models.CASCADE)
text = models.TextField()
并且我想选择有一些注释的发票。我将使用annotate
/ Exists
这样写它:
Invoice.objects.annotate(has_notes=Exists(Note.objects.filter(invoice_id=OuterRef('pk')))).filter(has_notes=True)
这效果很好,仅过滤带有注释的发票。但是,此方法导致字段出现在查询结果中,这我不需要,并且意味着性能较差(SQL必须执行两次子查询)。
我知道我可以像这样使用extra(where=)
编写此代码:
extra(where=)
这将产生理想的SQL,但通常不建议使用Invoice.objects.extra(where=['EXISTS(SELECT 1 FROM note WHERE invoice_id=invoice.id)'])
/原始SQL。有更好的方法吗?
[好,我刚刚在extra
中注意到,他们已经更新了Django 3.0 docs的工作方式,并且可以直接在Exists
中使用:
filter
这将确保子查询不会被添加到SELECT列中,这可能会导致更好的性能。
在Django 3.0中已更改:
在以前的Django版本中,必须先进行注释,然后再对注释进行过滤。这导致带注释的值始终出现在查询结果中,并且经常导致查询花费更多的时间来执行。
[不过,如果有人知道Django 1.11的更好方法,我将不胜感激。我们确实需要升级:(