【问题标题】:Arbitrary joins in Django Models任意加入 Django 模型
【发布时间】:2011-08-04 15:10:31
【问题描述】:

假设模型X 有一个字段n(一个整数)。现在我还有一个模型Y,其中有字段nm(整数)。是否可以使用 Django ORM 来选择 x(模型 X)使得存在 y(模型 Y)使得 x.n = y.ny.m = m 对于给定值 m

请不要建议我在两个模型之间引入ForeignKey 关系或类似的东西。我想具体知道是否可以在不修改模型的情况下实现这一目标。在我正在研究的确切情况下,给定的关系是通用的。而泛型关系的反面可以是任何东西,所以根据文档我不能在不同的模型中多次介绍GenericRelation

【问题讨论】:

  • 只有我一个人,还是功能上的严重差距?它怎么可能不是微不足道的?我开始认为他们将代码保存在 svn 中是一个不好的迹象。
  • 在 Django 世界中,没有你想象的那么严格。如果您想进行任意连接,原始 SQL(返回真实模型对象)可以满足您的需求。而且...你知道,我也喜欢 git 和 Mercurial,但如果说对开源项目最大的抱怨是它对源代码控制工具的品味,那简直就是天堂。
  • @Christophe 原始 SQL 的问题是您需要手动生成表名和列名。而且我认为它使当前的交易变得肮脏。我知道这是可能的,但是如果每次我需要做一些有点不标准的事情,我需要求助于手工编写 SQL,我宁愿根本不使用 ORM。在使用 Django ORM 一段时间后,我认为它在设计上被严重破坏了。

标签: python django django-models join django-orm


【解决方案1】:

我想这可以使用extra QuerySet 方法来实现。

(我没有测试过)

X.objects.extra(where=["x.n in (select y.n from y where y.m = '%s')"], params=['m_value'])

【讨论】:

  • 嗯,它确实在命名的一些小改动后工作。根据我读到的内容,它的性能也比普通的 JOIN 好。谢谢。
  • queryset.query.get_initial_alias() 获取分配给查询中主表的别名。 SomeModel._meta.db_table 也有任何模型的基础表名。
【解决方案2】:

您可以使用原始 sql 执行此操作:

def my_custom_sql(m):
    from django.db import connection, transaction
    cursor = connection.cursor()

    # Data retrieval operation - no commit required

    command = """SELECT * 
      FROM tX 
INNER JOIN tY
        ON (tX.n=tY.n AND tY.m=%s)"""

    cursor.execute(command % str(m))
    rows = cursor.fetchall()

    return rows

使用 ORM,我认为您可以使用 values_listin 过滤器来做到这一点:

class X(models.Model):
    n = models.IntegerField()

class Y(models.Model):
    n = models.IntegerField()
    m = models.IntegerField()

xs = X.objects.filter(n__in=Y.objects.filter(m=m).values_list('n')).distinct()

编辑: 如 cmets 所述,此方法会对数据库造成很大影响

【讨论】:

  • 请注意:以@kriegar 所做的第二种方式执行此操作将导致每个 X 对象对数据库的 O(n + 1) 次命中,非常糟糕!并强烈建议不要这样做。您应该使用他发布的第一种方法。
  • 嗯,第二种方法的问题在于它效率很低,因为它可能会将很长的值列表传输到数据库...第一种方法,我没有选择。也许我会尝试将其打包在经理中。但是我想我开始对这个框架产生仇恨。啊!!!
猜你喜欢
  • 2011-12-25
  • 2023-04-05
  • 1970-01-01
  • 2011-09-19
  • 2015-09-15
  • 1970-01-01
  • 2018-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多