【问题标题】:Using select_related and extra clause使用 select_related 和额外的子句
【发布时间】:2011-03-17 20:20:49
【问题描述】:

我正在尝试在查询集上实现一些额外的选择,并希望使用 select_related 方法将所需的表添加到查询中的表池中,以便受益于 '__' 语法。

这是一个简单模型的例子:

from django.db import models

# Create your models here.

class testA(models.Model):
    code = models.TextField(unique = True)
    date = models.DateTimeField(auto_now_add = True)

class testB(models.Model):
    text = models.TextField()
    a = models.ForeignKey(testA)

这是我要构建的查询:

SELECT (extract(hour from testa.date)) AS hour, testb.text FROM testb INNER JOIN testa ON (testb.a_id = testa.id)

这就是我在 python 中构建它的方式:

testB.objects.all().select_related('a').extra(select = {'hour' : 'extract(hour from testa.date)'}).values('hour','text')

但是当 django 发现我没有使用“testa”表(因为“values”语句)时,他删除了 select_related。所以生成的 SQL 查询失败:

SELECT (extract(hour from testa.date)) AS "hour", "testb"."text" FROM "testb"

如果我删除“值”语句,它可以正常工作:

SELECT (extract(hour from testa.date)) AS "hour", "testb"."id", "testb"."text", "testb"."a_id", "testa"."id", "testa"."code", "testa"."date" FROM "testb" INNER JOIN "testa" ON ("testb"."a_id" = "testa"."id")

但我必须将 values 语句放在我想要聚合的地方,如“计算 a 对象中按日期的小时分组的 b 对象”:

testB.objects.all().select_related('a').extra(select = {'hour' : 'extract(hour from testa.date)'}).values('hour').annotate(count = Count('pk'))

那么实现这一目标的好方法是什么? “计算按另一个对象中的某物分组的对象”?或者有没有办法“强制”django 保留“select_related”表,即使他认为它们没用?

PS:我知道我可以使用额外语句的“tables”参数,但在这种情况下,我必须自己重写连接,我想从 django ORM 中受益

【问题讨论】:

    标签: python django


    【解决方案1】:

    我开发了一个 Django 应用程序来解决此类问题:django-cube。基本思想是模拟多维数据库,以便轻松计算聚合。

    您需要的功能('__hour' : 'hour' 的字段查找)未实现,但实现它可能需要 15 分钟。所以请阅读接下来会发生什么,它是如何工作的,等等......如果它符合您的需要,请写信给我,我会实施它。

    主页上的示例和 api 文档不是最新的(它们将在几天内更新),但这些 snippets 是。如果你想试一试,下面是用 django-cube 解决这个问题的方法:

    #install the app first ...
    from cube.models import Dimension, Cube
    
    class MyCube(Cube):
        #declare a dimension called 'hour_a',
        #that is related to the field 'a__date__hour'.
        hour_a = Dimension(field='a__date__hour')
    
        #declare how to calculate the aggregation on a queryset
        @staticmethod
        def aggregation(queryset):
            return queryset.count()
    

    然后,有多种计算结果的方法,检查sn-ps...你可以例如使用:

    cube(testB.objects.all()).measure_dict('hour_a', full=False)
    

    这会返回类似:

    {   
        12: {measure: 889},
        13: {measure: 6654},
        14: {measure: 77},
        #<hour>: <count>
    }
    

    另外,不要下载特色下载,而是从源代码(分支 0.3)签出。

    我不知道你真正的需求是什么,对于你的使用来说可能有点重(最初是为了数据可视化目的而制作的)。

    【讨论】:

    • 如果它最初是为数据可视化而制作的,那正是我正在寻找的。我正在尝试构建的工具是一个允许用户通过“编写”这样的句子来查询数据库的工具:“我想计算具有 ObjectB.date > 20100101 并且具有 ObjectC.code = 'foo' groupe 的 ObjectA通过 ObjectA.code 和 ObjectC.category” UI 是 ajax,当用户选择第一个“模型”进行查询时,过滤器和分组选择填充可能的值。现在我正在尝试使用 SQLAlchemy,但我会看看 django-cube 谢谢
    【解决方案2】:

    我无法回答您的主要问题,但值得注意的是select_related__ 语法无关。 select_related 只是一种优化,它会返回额外的相关对象,如果需要的话,会在查询中添加连接。但是查询相关表的双下划线语法在有或没有 select_related 的情况下都有效。

    【讨论】:

      【解决方案3】:

      我在本地遇到同样的错误:在附加“值”之前一切正常,然后 django 无法放置适当的 FROM 子句。我会将这个示例发布到django-users 组,看看是否有人知道这是一个错误,或者是否有快速修复它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-12
        • 1970-01-01
        • 1970-01-01
        • 2015-07-28
        • 2015-09-25
        • 1970-01-01
        • 1970-01-01
        • 2010-12-09
        相关资源
        最近更新 更多