【问题标题】:django - guide to ORM for SQL users?django - SQL 用户的 ORM 指南?
【发布时间】:2011-01-13 05:51:58
【问题描述】:

django 内置了这个复杂的 ORM,但是在花了很多时间之后,我仍然很难在 SQL 中进行非常简单的查询。甚至有一些简单的事情我无法通过 django ORM 完成(例如,'select distinct column1 from tablename')。

是否有任何文档显示“对于常见的 SQL 语句,这是您在 django 中的操作方式”?

(我确实先尝试了谷歌,但要么它不存在,要么我想不出正确的查询......)

【问题讨论】:

    标签: sql django orm


    【解决方案1】:

    SQL 中有一些简单得离谱的事情通过 ORM 很难或不可能。这称为“object-relational impedance mismatch”。本质上,ORM 将数据库中的每一行视为一个单独的对象。因此,涉及将值与行分开处理的操作变得相当具有挑战性。最新版本的 Django (1.1+) 使用 aggregation support 在一定程度上改善了这种情况,但在很多情况下,只有 SQL 可以工作。

    为此,django 提供了几种方法让您非常简单地进入原始 sql。其中一些将模型对象作为结果返回,而另一些则将您一路带到 DBAPI2 连接器。最底层的样子是这样的:

    from django.db import connection
    
    cursor = connection.cursor()
    cursor.execute("SELECT DISTINCT column1 FROM tablename")
    row = cursor.fetchone()
    

    如果您想从 SQL 查询返回查询集,请使用模型管理器上的 raw():

    qs = ModelName.objects.raw("""SELECT first_name 
                                  FROM myapp_modelname 
                                  WHERE last_name = 'van Rossum'")
    for person in qs:
         print person.first_name # Result already available
         print person.last_name  # Has to hit the DB again
    

    注意: raw() 仅在 Django 的开发版本中可用,从 1.2 开始应该合并到主干中。

    完整信息可在Performing raw SQL queries 下的文档中找到。

    【讨论】:

    • 这是为我做的。关键是ORM提取了一组对象(“object”~=“entire row”),但是SELECT DISTINCT的结果行不能连接到单个对象。因此,如果您需要对象,请使用 ORM;如果您需要无法可靠地将行映射到单个对象的结果,请直接使用 SQL。谢谢。
    【解决方案2】:

    这样想。

    “对于常见的 SQL hack-arounds,我最初应该做的面向对象的事情是什么?”

    问题不在于 ORM 很复杂。就是你的大脑已经被SQL模具扭曲了,很难看清物体。

    一般规则:

    • 如果您认为这是一个简单的 SELECT FROM WHERE,请停止。询问您需要在结果集中看到哪些对象。然后找到这些对象并使用对象管理器。

    • 如果您认为这是一个简单的 JOIN,请停止。询问您想要什么主要对象。请记住,对象不使用外键。加入没有任何意义。一个对象似乎打破了 1NF 并在其中包含整个相关对象集。然后找到“主要”对象并使用对象管理器。使用相关对象查询来查找相关对象。

    • 如果您认为这是一个 OUTER JOIN,请停止。询问您希望在结果集中看到哪两件事。外部连接是将 UNIONED 与不会连接的事物连接起来的事物。首先是什么东西。然后找到“主要”对象并使用对象管理器。有些会有一组相关的对象。有些不会。

    • 如果您认为它是 WHERE EXISTS 或 WHERE IN 子查询,则您的模型可能不完整。有时,它需要一个花哨的连接。但是如果你在做这种检查,这通常意味着你的模型中需要一个属性。

    • 如果您认为您需要 SELECT DISTINCT,那么您完全错失良机。那只是一个 Python 集。您只需将列值放入 Python 集中。这些是不同的值。

    • 如果您认为您需要 GROUP BY,那么您将忽略 Python collections.defaultdict。使用 Python 进行 GROUP BY 通常比使用 SQL 更快。

      数据仓库除外。你不应该在 Django 中这样做。您必须使用 SQLAlchemy 进行数据仓库。

    【讨论】:

      【解决方案3】:

      进行 Django 查询的一个很好的起点是 Django 文档本身。

      http://docs.djangoproject.com/en/dev/topics/db/queries/

      这里有几个例子:

      select * from table
      =
      ModelName.objects.all()
      

      过滤:

      select * from table where column = 'foo'
      =
      ModelName.objects.filter(column='foo')
      

      特别是关于 distinct 的使用,您使用 Django 查询集的 distinct() 方法。

      这是文档中的相关链接。 http://docs.djangoproject.com/en/dev/ref/models/querysets/#distinct

      更新: ORM 通过允许您使用面向对象的数据交互来帮助您。您不会编写将查询结果集转换为一组对象的代码。它会自动完成。这是您必须对思维过程做出的根本性改变。

      您开始考虑“我有这个对象,我需要获取所有其他类似的对象”然后您可以向 ORM 询问这些对象。 ORM,我需要所有具有颜色“蓝色”属性的产品类对象

      Django 的特定 ORM 语言是:

      products = Product.objects.filter(color='blue')
      

      这样做是为了代替:

      • 编写您的 sql 查询,
      • 正确转义所有参数,
      • 连接到数据库,
      • 查询数据库并处理连接/查询错误,
      • 获取结果集,
      • 遍历结果集,将返回的值转换为可以调用方法的适当对象。

      这就是使用 ORM 的价值所在。代码简化并缩短了开发时间。

      【讨论】:

      • 当然,我在询问之前阅读了文档,但在现代世界中,我可以理解为什么您可能会做出其他假设。我的问题是文档没有非常有效地回答我的问题。我从来没有发现 RDBMS 难以理解,而且完全不清楚 ORM 应该如何“帮助”我。我希望能找到“旅行者的短语手册:面向 SQL 使用者的 Django”。
      • 为你更新了我的答案,我希望这有助于更多地解释思考过程。
      【解决方案4】:

      对于您的具体操作方法,您可以这样做:

      MyModel.objects.values_list('column1', flat=True).distinct()
      

      但是其他发帖人说你不应该想'我如何在 ORM 中编写这个 SQL' 是正确的。当您从 Java 或 C++ 或其他学习 Python 时,您很快就学会了摆脱“我如何用 Python 编写 Java 代码”的思维定势,而专注于使用 Python 解决问题。使用 ORM 也应该如此。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-21
        • 2013-12-05
        • 2014-03-24
        • 2012-12-15
        • 2021-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多