如何使用Django ORM执行这个复杂的SQL查询?(带连接的子查询)

3 投票
2 回答
1697 浏览
提问于 2025-04-16 06:12

我习惯自己写SQL查询,现在想适应一下现在很流行的ORM(对象关系映射)方式。

这是我的查询:

SELECT * FROM routes WHERE route_id IN (
    SELECT DISTINCT t.route_id FROM stop_times AS st 
    LEFT JOIN trips AS t ON st.trip_id=t.trip_id
    WHERE stop_id = %s
)

这里的 %s 是一个整数。

我在用Django的默认ORM。请问用Python的方式怎么做这个比较好呢?

一些背景信息:我使用的数据库来自GTFS(谷歌交通信息规范)。这个查询是为了获取经过特定 stop 的每条 route,但这些信息是在 trips 表里。

这个查询对我来说运行得很好,所以我问这个问题只是想学习一下。

谢谢!

2 个回答

1

如果我说错了请纠正我,但我觉得用Django的ORM(对象关系映射)是无法以正常方式做到这一点的。

它不支持子查询,使用普通的连接查询的话,能否使用distinct(去重)要看你的数据库。如果你使用的是Postgres数据库,那么可以通过这个补丁来实现:http://code.djangoproject.com/ticket/6422

查询的写法大概是这样的:

Route.objects.filter(stop_time__trips__stop_id=...).distinct('stop_time__route_id')
1

如果你能提供一下你用的相关 Models,那可能会更容易找到合适的解决办法。

我根据你提到的规范,假设你的模型大概是这样的:

class Route(models.Model):
    #bunch of stuff
    pass
class Stop(models.Model):
    #bunch of stuff
    stop_times = models.ManyToManyField(through=StopTime)
class StopTime(models.Model):
    trip = models.ForeignKey(Trip)
    stop = models.ForeignKey(Stop)
    # bunch of additional meta about this M2M table
    pass
class Trip(models.Model):
    route = models.ForeignKey(Route)
    # bunch of stuff

如果是这样的话……你应该可以做类似下面的操作:

Route.objects.filter(trip__stop__id=my_stop_id)

这样就能获取到所有经过某个特定 StopRoute 对象,前提是这个 Stop 的主键 id 等于 my_stop_id,我假设这个值是个整数,正如你帖子里提到的。

如果语法有点不对,我先说声抱歉,因为我之前没怎么用过需要额外表的多对多关系。如果你需要(或者选择)为任何外键或多对多字段使用 related_name 参数,可能还需要做一些调整。

撰写回答