Django LEFT JOIN?

时间:2009-09-14 03:15:58

标签: python django

我有模特,或多或少是这样的:

class ModelA(models.Model):
    field = models.CharField(..)

class ModelB(models.Model):
    name = models.CharField(.., unique=True)
    modela = models.ForeignKey(ModelA, blank=True, related_name='modelbs')

    class Meta:
        unique_together = ('name','modela')

我想做一个查询,其中包括:“获取所有ModelA的字段名称等于X,其中ModelB模型的名称为X OR,根本没有模型名称”

到目前为止,我有这个:

ModelA.objects.exclude(field=condition).filter(modelsbs__name=condition)

这将使我获得至少有一个modelB的所有ModelAs(实际上它总是只有一个) - 但是如果ModelA没有相关的ModelB,它将不在结果集中。我需要它在结果集中使用obj.modelb = None

之类的东西

我该如何做到这一点?

4 个答案:

答案 0 :(得分:11)

使用Q结合两个条件:

from django.db.models import Q
qs = ModelA.objects.exclude(field=condition)
qs = qs.filter(Q(modelbs__name=condition) | Q(modelbs__isnull=True))

检查生成的SQL查询:

print qs.query.as_sql()

在类似的查询中,这将生成LEFT OUTER JOIN ... WHERE(a.val = b或a.id IS NULL)。

答案 1 :(得分:1)

看起来你正面临着80%的障碍。为什么不使用.extra(select={'has_x_or_none':'(EXISTS (SELECT ...))'})来执行子查询?您可以按照自己喜欢的方式编写子查询,并且应该能够针对新字段进行过滤。 SQL应该看起来像这样:

SELECT *, 
  ((EXISTS (SELECT * FROM other WHERE other.id=primary.id AND other.name='X'))
    OR (NOT EXISTS (SELECT * FROM other WHERE other.id=primary.id))) AS has_x_or_none
  FROM primary WHERE has_x_or_none=1;

答案 2 :(得分:1)

尝试使用此修补程序进行自定义联接:https://code.djangoproject.com/ticket/7231

答案 3 :(得分:-3)

LEFT JOIN是两个查询的联合。有时它会针对一个查询进行优化。有时,它实际上并没有被底层SQL引擎优化,而是作为两个单独的查询完成的。

这样做。

for a in ModelA.objects.all():
    related = a.model_b.set().all()
    if related.count() == 0:
        # These are the A with no B's
    else:
        # These are the A with some B's

不要迷恋SQL外部联接似乎是“单一”查询。