使用 annotate() 包含一个 django 模型对象属性
Posted
技术标签:
【中文标题】使用 annotate() 包含一个 django 模型对象属性【英文标题】:Include a django model object property using annotate() 【发布时间】:2018-10-28 08:10:10 【问题描述】:我有一个包含 @property
的模型,我希望在执行以下操作时包含该模型
vals = MyModel.objects.values()
Another S/O post 建议这样做的方法是重写管理器类的 get_queryset
方法,并通过调用 annotate(xtra_field=...)
来增强。
问题是我找不到如何使用模型属性执行此操作的示例。我尝试过类似的东西
super(SuperClass, self).get_queryset().annotate(xtra_fld=self.model.xtra_prop)
及其众多变体,但都不起作用。
问题,我认为注释参数的 RHS 应该是什么?
(而且,是的,我知道还有其他更笨重的方法可以做到这一点,比如迭代 values()
返回的内容并在我去的时候添加属性。对我来说,这不是一个非常优雅(甚至是 django)的解决方案.
【问题讨论】:
@property
不能这样做,因为属性处于 Python 级别。数据库对属性一无所知。
是的,现在我想起来了。在进一步的研究中,我认为解决方案将是创建一个可以构造/解构实际 db 字段的自定义字段。我所做的与文档中的Hand
示例没有什么不同。
【参考方案1】:
除非您在数据库中生成属性值,否则您无法在不覆盖 django 的内部方法的情况下执行此操作 - 我建议不要这样做。
一个更优雅的解决方案可能是向a custom queryset 添加一个额外的方法,它会根据请求生成额外的字段:
from django.db import models
class AreaQuerySet(models.QuerySet):
def values_with_area(self, *fields):
# width & height are always required to calculate the area
fields = set(fields)
fields.update(['width', 'height'])
for row in self.values(*fields):
row['area'] = Widget.calculate_area(row['width'], row['height'])
yield row
class Widget(models.Model):
# ...
objects = AreaQuerySet.as_manager()
@classmethod
def calculate_area(cls, width, height):
return width * height
@property
def area(self):
return Widget.calculate_area(self.width, self.height)
【讨论】:
我认为您的意思是在 Widgets 模型中将 AreaQuerySet 引用为管理器。 这样的事情可能会奏效。但是,我觉得这是一个更复杂的解决方案。我希望它是某种语义,例如双下划线。也就是说:...annotate(xtra_field='self__xtraproperty')
。 应该就这么简单。以上是关于使用 annotate() 包含一个 django 模型对象属性的主要内容,如果未能解决你的问题,请参考以下文章
072:Django数据库ORM聚合函数详解-aggregate和annotate
Django基础aggregate和annotate方法使用详解与示例
Django Annotate - 我可以将在 annotate 中创建的字段用于在 annotate 中创建的另一个字段吗?
使用 annotate Exists 时提高 Django 查询集性能