【问题标题】:How to use Django Orm Subqueries in this sql如何在这个 sql 中使用 Django Orm 子查询
【发布时间】:2019-08-16 18:36:14
【问题描述】:

我是Django ORM 的新手,我发现在sql 语句中使用Django 子查询很困难,因为我没有在django orm 中找到嵌套的select .. from (select... 示例:

这些是我的模型:

class A:
     published_at = models.DateTimeField(_('Published at'))
     ....

Class B:

     pub=models.ForeignKey('A', verbose_name=_('A'), blank=True, null=True,
                          on_delete=models.SET_NULL)
     prices= models.FloatField(_('Price'), blank=True, null=True, db_index=True)
     soc = models.IntegerField(_('SOC'), blank=True, null=True,
                               db_index=True)

这是SQL

select DATE_FORMAT(`A`.`published_at`, '%Y-%m-%d'), sum(b)
    from (
   select `B`.`pub_id` as c, soc, avg(prices) as b
   from B
   group by c, soc
    ) as ch
   INNER JOIN `A` ON (c = `A`.`id`)
   group by DATE_FORMAT(`A`.`published_at`, '%Y-%m-%d');

在这种情况下使用“子查询”有用吗?我正在使用 django 1.11

请帮忙

更新

当我尝试Endre Both 建议的解决方案时,我得到了这个错误

           Traceback (most recent call last):
      File "/home/vagrant/.local/lib/python3.6/site- 
       packages/IPython/core/interactiveshell.py", line 3296, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
        File "<ipython-input-7-824230af12bd>", line 5, in <module>
.annotate(total=Sum('avg'))
      File "/home/vagrant/.local/lib/python3.6/site-packages/django/db/models/query.py", line 948, in annotate
clone.query.add_annotation(annotation, alias, is_summary=False)
      File "/home/vagrant/.local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 973, in add_annotation
summarize=is_summary)
       File "/home/vagrant/.local/lib/python3.6/site-packages/django/db/models/aggregates.py", line 19, in resolve_expression
c = super(Aggregate, self).resolve_expression(query, allow_joins, reuse, summarize)
     File "/home/vagrant/.local/lib/python3.6/site-packages/django/db/models/expressions.py", line 548, in resolve_expression
c.source_expressions[pos] = arg.resolve_expression(query, allow_joins, reuse, summarize, for_save)
      File "/home/vagrant/.local/lib/python3.6/site-packages/django/db/models/expressions.py", line 471, in resolve_expression
return query.resolve_ref(self.name, allow_joins, reuse, summarize)
        File "/home/vagrant/.local/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1472, in resolve_ref
return self.annotation_select[name]
    KeyError: 'avg'

【问题讨论】:

  • 如果 SQL 语法有效(我不认为它是有效的,你运行了吗?),你似乎加入了两个主键。我不明白这有什么意义。
  • 如果两个模型之间有关系,用Django relationships表示。
  • 是的,有一个我忘记提及的relashionship..你能看看我的编辑吗

标签: django django-orm


【解决方案1】:

如果您首先要计算 pub_idsoc 的平均价格,然后对发布日期相同的酒吧的平均价格求和,您可能正在寻找这个:

from django.db.models import FloatField, OuterRef, Subquery, Sum, Avg

sq = Subquery(B.objects
               .filter(pub_id=OuterRef('id'), soc=OuterRef('b__soc'))
               .values('pub_id', 'soc')
               .annotate(avg=Avg('prices'))
               .values('avg'),
              output_field=FloatField()
             )

results = (A.objects
            .values('id', 'published_at', 'b__soc')
            .annotate(avg=sq)
            .values('published_at')
            .annotate(total=Sum('avg'))
           )

我是瞎写的,我很好奇我是否写对了。这可能是原始 SQL 查询更容易理解的情况之一。

顺便说一句,在没有任何加权的情况下总结平均值有什么用处?

【讨论】:

  • 感谢您的好评。实际上,当我运行results 的代码时,它在annotate 中给了我一个错误NameError: name 'avg' is not defined
  • 我不明白为什么会发生这种情况。尝试将第二个(结果)查询中的 avg 重命名为其他名称(两次都出现),以查看问题出在子查询还是主查询中。
  • 我试过了,但同样的错误发生了。我什至尝试删除引号。
  • 你使用什么 Django 版本?它适用于我的 2.1。您必须在问题中包含完整的堆栈跟踪才能了解更多信息。
  • 我正在使用 django 1.11.. 好的,等一下我会做的
猜你喜欢
  • 2018-08-03
  • 1970-01-01
  • 2023-03-03
  • 2010-10-06
  • 1970-01-01
  • 2018-06-10
  • 1970-01-01
  • 2022-01-21
  • 2017-04-12
相关资源
最近更新 更多