在 SQLAlchemy 中,“过滤器”与“连接和过滤器”语法有什么区别?

ali*_*dry 3 python sql postgresql sqlalchemy

更具体地说,我发现很多人在 SQLAlchemy 中没有使用类似 SQL 的自然连接语法,而是倾向于使用过滤器来进行连接。在这里详细说明我将如何进行连接:

(session.Query(Book)
        .join(Author, Publisher, Retailer)
        .filter(
            Author.name == "Crenshaw Adams",
            Publisher.country == "United States",
            Retailer.is_online == True))
Run Code Online (Sandbox Code Playgroud)

连接列隐含在模型声明文件中定义的关系中。

但在其他地方(尤其是在 StackOverflow 上),我看到人们这样做:

(session.Query(Book)
        .filter(
            Book.author_id == Author.id,
            Author.publisher_id == Publisher.id,
            Publisher.retailer_id == Retailer.id,
            Author.name == "Crenshaw Adams",
            Publisher.country == "United States",
            Retailer.is_online == True
            ))
Run Code Online (Sandbox Code Playgroud)

以下哪种方法是正确的方法?哪个更 Pythonic?或者,至少,应该使用 SQLAlchemy 的方式更惯用?并且在DB资源使用或本地机器资源使用方面有区别吗(即DB的CPU和RAM压力更大,本地机器更少,反之亦然)?

此外,前一种方法不允许update()使用 Query API 上的方法 - 它抱怨不允许多表更新 - 即使我只更新一个表。后者允许update()正常工作。

Ilj*_*ilä 5

主要区别在于前者导致查询使用SQL-92 JOIN语法,而后者使用旧语法——例如,有些人出于习惯而更喜欢它。两者都是正确的方法,并且与代码是否为 Pythonic 没有太大关系。同样在我看来,SQLAlchemy 中也没有更惯用的,尽管Query.join()正如您自己指出的那样与定义的外键关系和 ORM 关系配合得很好。它们还应该在现代 SQL DBMS 中产生相同的执行计划,因此在资源使用等方面没有有意义的差异。

至于Query.update()不支持显式连接,不同的 SQL DBMS 对多表更新的支持不同,使用不同的语法和方法。有些允许显式连接,有些不允许,有些允许通过子查询更新。当前的实现似乎是一种妥协,并将呈现为UPDATE正在使用的 DBMS 的合适语句。