【问题标题】:Django : aggregation down to specific level after annotation() & value()Django:在注释()和值()之后聚合到特定级别
【发布时间】:2017-05-23 20:58:08
【问题描述】:

我正在尝试使用 Django 将值聚合到特定级别,但它似乎并不直截了当:聚合发生在完整的查询集或对象级别,而不是“中间”。

这是我的查询:我需要从多个事件条目中逐年计算总活动时间。

events.annotate(                      # Extracting the year
       year = ExtractYear('dtstart')
   ).annotate(                        # Computing duration... 
       time_span= ExpressionWrapper(
               F('dtend') - F('dtstart'), 
               output_field=IntegerField()
           )
   ).values(                          # ... then aggregating by year
       'year', 'time_span'             #!!!! ... BUT ALSO unfortunately
                                      # by 'time_span' !!!!!!!!!!!!!!!
   ).annotate(                        # otherwise 'time_span' would not
       total_span=Sum('time_span')    # be available for a new computation.
   ).values(                          # Therefore, the result is not
       'year', 'total_span'           # grouped by year, but by the
   ).order_by(                        # distinct combination of 'year'
       'year'                         # AND 'total_span'
   )

因此,我得到了这个结果:

<QuerySet [
{'total_span': 1800000000, 'year': 2016}, 
{'total_span': 7200000000, 'year': 2016}, 
{'total_span': 2700000000, 'year': 2016}, 
{'total_span': 14400000000, 'year': 2016}, 
{'total_span': 8100000000, 'year': 2017}, ...>

而不是这样的:

<QuerySet [
{'total_span': 16700000000, 'year': 2016}, 
{'total_span': 19800000000, 'year': 2017}, ...>

为了设置聚合级别,我需要类似的东西:

聚合(total_span=Sum('time_span'), group_by='year')

我想我应该转向子查询或自定义聚合类,但这超出了我的技能范围。任何提示将不胜感激...

【问题讨论】:

    标签: python django aggregate annotate


    【解决方案1】:

    我认为这可能是您要回归基础并编写一些 SQL 的情况之一。 ORM 很棒,但有时尝试使用它需要做更多的工作,然后才默认恢复正常工作。您可能可以让它与 ORM 一起工作,但这可能更容易。

    from django.db import connection
    
    cursor = connection.cursor()
    cursor.execute("""
        select
          sum(dtend - dtstart) as total,
          DATE_FORMAT(dtstart, "%Y") as year
        from events
        group by year;""")
    
    for row in cursor.fetchall():
        # Do something with it
    

    编辑:与往常一样,请确保清理您可能通过原始 SQL 输入的任何用户输入

    【讨论】:

      猜你喜欢
      • 2011-12-20
      • 1970-01-01
      • 2016-11-18
      • 2015-12-29
      • 2016-01-30
      • 2023-03-29
      • 2015-01-08
      • 2021-01-20
      • 2011-07-07
      相关资源
      最近更新 更多