使用 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 查询集性能

Django:仅使用 annotate() 和 values() 计算非空 CharField

aggregate和annotate使用