如何在Django中创建复杂的左连接

2 投票
1 回答
1044 浏览
提问于 2025-04-18 01:41

我正在尝试使用Django创建多个模型的左连接。

这是我的模型:

class LookupTiming(models.Model):
    day = models.CharField(max_length=7)
    time_1 = models.TimeField()
    time_2 = models.TimeField()

    class Meta:
        db_table = u'lookup_timing'

class Streets(models.Model):
    name = models.CharField(max_length=50)
    point = models.GeometryField(null=True, blank=True)
    objects = models.GeoManager()

    class Meta:
        db_table = u'streets'

    def __unicode__(self):
        return '%s' % self.name


class StreetTimings(models.Model):
    street= models.ForeignKey(Streets)
    lookuptiming = models.ForeignKey(LookupTiming)
    class Meta:
        db_table = u'street_timings'

这是我创建的查询:

Streets.objects.filter(streettimings__isnull=True).filter(streettimings__lookuptiming__isnull=True).values('id')

这是上面查询的SQL输出:

SELECT "streets"."id" FROM "streets"
LEFT OUTER JOIN "street_timings" ON ( "streets"."id" = "street_timings"."street_id" ) 
LEFT OUTER JOIN "street_timings" T3 ON ( "streets"."id" = T3."street_id" )
WHERE ("street_timings"."id" IS NULL AND T3."lookuptiming" IS NULL)

但我想要以下查询:

select st.id from streets st
LEFT JOIN street_timings timing on timing.street_id = st.id 
LEFT JOIN lookup_timing lt on lt.id = timing.lookuptiming_id 

所以问题是,Django的查询完全忽略了lookuptiming模型。我想创建以下连接:

Streets(id) = StreetTimings (street_id)

LookupTiming (id) = StreetTimings (lookuptiming_id)

我该如何为多个模型创建左连接呢?

谢谢!

1 个回答

3

你的问题是关于Django查询的。

Streets.objects.filter(streettimings_isnull=True).filter(streettimings_lookuptiming__isnull=True).values('id')

streettimings_isnull=True 会返回那些没有 StreetTiming 关系的 Streets。所以,使用 streettimings_lookuptiming__isnull=True 是没有意义的,因为过滤后的 Street 对象根本就没有相关的 StreetTiming 关系。你可以试试下面的方法。

LookupTiming.object.values_list("streettimings__street__id", Flat=True)

如果这样做没有得到你想要的查询结果,你可以尝试下面的方法。

LookupTiming.object.filter(streettimings__street__isnull=False).values_list("streettimings__street__id", Flat=True)

这样会返回所有的 Street.Id 值。你需要使用反向关系来创建你想要的查询。

更新:必须在过滤(或者查询API的其他部分)中使用关系,这样Django才能创建 joins。如果你不提供任何过滤数据,Django就不会创建 joins,因为它认为不需要。

你可以尝试下面的方法,但即使这样也会创建一个 WHERE 子句。

Streets.objects.filter(streettimings_lookuptiming__id__gt=0).values('id')

撰写回答