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

问题描述 投票:1回答:1

我正在使用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应该有一个计算字段(timedelta称为delta),显示它发生在前一个事件之后多少。因为Event的时间可以改变,所以在运行时计算这个timedelta似乎更好,而不是将其存储在数据库中(保持数据库中最新的增量变得毛茸茸,例如,如果事件的时间以改变方式的方式发生变化事件序列,即一个事件“跳过”另一个事件。

所以我有一个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

当我现在“使用”它时,例如在模板中

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

或者像这样的代码

events = thing.event_set.all()

然后没有设置event.deltaevents.delta。即使看起来(我不知道如何证明)自定义管理器(EventManager)被使用/调用。

我不确定问题是我不能更改查询集(即# fake calculation的行是问题),或者这是否与Base managers documentation中的以下语句有关

查询相关模型时不使用基本管理器。

或者完全不同的东西。

任何指针都非常感谢。

python django django-models django-queryset django-managers
1个回答
1
投票

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

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.