使用select_related和extra子句

时间:2010-07-19 10:17:19

标签: python django

我正在尝试在查询集上实现一些额外的选择,并希望使用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"

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

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")

但是我必须把值语句放在我想要聚合的位置,如“计算按对象中日期的小时分组的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中受益

3 个答案:

答案 0 :(得分:1)

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

您需要的功能('__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()

然后,有各种方法来计算结果,检查片段...例如你可以使用:

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

会返回类似的内容:

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

另外,不要进行精选下载,而是从源代码检出(分支0.3)。

我不知道您的真正需求是什么,对于您的使用可能会有点沉重(最初是出于数据可视化目的)。

答案 1 :(得分:0)

我无法回答您的主要查询,但值得注意的是select_related__语法无关。 select_related只是一个优化,它将返回额外的相关对象,如有必要,可以在查询中添加连接。但是查询相关表的双下划线语法可以使用或不使用select_related。

答案 2 :(得分:0)

我在本地得到相同的错误:一切正常,直到附加“values”,然后django无法放置适当的FROM子句。我会将此示例发布到django-users组,看看知情人是否可以验证这是否是一个错误,或者是否有一个快速修复它。