自定义管理器并不总是为多对一关系添加计算字段

Custom Manager not always adding calculated field for many-to-one relationship

我正在为一个项目使用 Django 2.1。我的一个 Models(在下例中称为 Event)与另一个 Model(在下例中称为 Thing)具有多对一关系。第一个模型应该有我认为的计算字段。

举例说明:

class Thing(models.Model):
    ...

class Event(models.Model):
    ...
    thing = models.ForeignKey(Thing, on_delete=models.CASCADE)
    ts = models.DateTimeField(default=django.utils.timezone.now)
    _delta = timedelta()
    ...
    objects = EventManager()

    @property
    def delta(self):
        return self._delta

    @delta.setter
    def delta(self, value):
        self._delta = value

一个 Event 应该有一个计算字段(一个称为 deltatimedelta),显示它发生在前一个事件之后的时间。因为 Event 的时间可能会改变,所以最好在 运行 时间计算这个 timedelta 而不是将其存储在数据库中(让数据库中的增量保持最新变得毛茸茸的,例如,如果一个事件的时间以一种改变事件顺序的方式发生变化,即一个事件 "jumps" 超过另一个事件)。

所以我有 Event

的自定义管理器
class EventManager(models.Manager):

    def get_queryset(self):
        qs = super().get_queryset()
        for r in qs:
            r.delta = django.utils.timezone.now() - r.ts  # fake calculation
    return qs

当我现在 "use" 这个,例如在模板中

{% for event in thing.event_set.all|dictsortreversed:"ts" %}

或者像这样的代码

events = thing.event_set.all()

则未设置event.deltaevents.delta。尽管 似乎 (我不知道如何证明)自定义管理器 (EventManager) 是 used/called.

我不确定问题是我无法更改查询集(即带有 # fake calculation 的行是问题所在)还是与 Base managers documentation 中的以下语句有关

Base managers aren’t used when querying on related models.

或完全不同的东西。

非常感谢任何指点。

在大多数情况下,管理器返回的查询集(此处:EventManager)不用作实例列表,而是用作查询定义。唯一的例外是调用 Event.objects.all() 时。这是唯一实际使用 r 对象的情况。在所有其他情况下,向它们添加字段 delta 是浪费时间,因为它们根本不会被使用。

你可以做的是定义一个方法,可以在 class 的实例上调用它来根据请求进行任何计算:

class Event(models.Model):
    def delta(self):
        return django.utils.timezone.now() - self.t

您也可以使用此方法在模板中进行排序。

另一种方法是在视图中添加您需要的任何计算字段(但同样,您需要注意在模板中访问时不修改查询集,否则会发出新查询,对象将被重新实例化,您在视图中添加的任何字段都将丢失。