【问题标题】:Django ORM group by a custom Func自定义 Func 的 Django ORM 组
【发布时间】:2020-01-09 09:26:49
【问题描述】:

我正在使用 Django,我需要通过自定义函数对模型进行分组。

好的,我想要的查询是:

SELECT date_trunc('week',"model_table"."date") AS "date" FROM "model_table" GROUP BY "date"

然后我尝试的是以下内容:

class DateTrunc(Aggregate):
    function = 'date_trunc'
    template = "%(function)s('%(date_type)s',%(expressions)s)"
    date_types = ['microsecond', 'millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year', 'decade', 'century', 'millenium']

    def __init__(self, date_type, expression, group_by=False, **extra):
        self.must_group_by = group_by  # Name "group_by" is already used.
        if date_type not in self.date_types:
            raise AttributeError('The specified "date_type" is not correct.')
        super().__init__(expression, date_type=date_type, **extra)

    def get_group_by_cols(self):
        if self.must_group_by:
            return [self]
        return super().get_group_by_cols()

In [1]: Model.objects.annotate(date=DateTrunc('week','date',True)).values('date').query.__str__()                                   
Out[1]: 'SELECT date_trunc(\'week\',"model_table"."date") AS "date" FROM "model_table" GROUP BY "model_table"."id", date_trunc(\'week\',"model_table"."date")'

除了GROUP BY 子句还插入表唯一ID 之外,其他方法都可以找到。这意味着最终结果根本没有分组。

我一直在检查 Django 代码,在 Query 类中有一个函数 set_group_by 把它弄得一团糟,但我真的不知道如何破解它。

无论如何,我认为正确的方法是继承 Func 类而不是 Aggregate,但是我无法让 Djangot 在最终 SQL 中插入 GROUP BY 子句。

知道如何在不使用cursorRawSQL 或其他直接编写查询的方式对查询进行硬编码的情况下解决这个问题吗?

【问题讨论】:

    标签: python django postgresql orm


    【解决方案1】:

    好的,我找到了一种使用Func 的方法,尽管它只是一个补丁。 因此,首先要制作如下自定义函数:

    class DateTrunc(Func):
        function = 'date_trunc'
        template = "%(function)s('%(date_type)s',%(expressions)s)"
        date_types = ['microsecond', 'millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year', 'decade', 'century', 'millenium']
    
        def __init__(self, date_type, expression, **extra):
            if date_type not in self.date_types:
                raise AttributeError('The specified "date_type" is not correct.')
            super().__init__(expression, date_type=date_type, **extra)
    

    然后我们有一个简单的自定义函数,我们的查询可以是:

    In [7]: Model.objects.annotate(date=DateTrunc('week','date')).values('date').annotate(Avg('parameter')).query.__str__()                                       
    Out[7]: 'SELECT date_trunc(\'week\',"model_table"."date") AS "date", AVG("model_table"."parameter") AS "parameter__avg" FROM "model_table" GROUP BY date_trunc(\'week\',"model_table"."date")'
    

    在这个解决方案中,parameter 或聚合函数 Avg 可以是任意的,不会被使用。只是让 Django 按我想要的日期分组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      • 2021-07-02
      • 2016-01-09
      • 2010-11-17
      • 2017-10-01
      相关资源
      最近更新 更多