Custom Manager并不总是为多对一关系添加计算字段

时间:2019-03-20 06:54:35

标签: python django django-models django-queryset django-managers

我正在将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的{​​{1}}),该字段显示上一次事件发生后发生了多少。由于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.delta。即使似乎(似乎不知道如何证明)使用/调用了自定义管理器(events.delta)。

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

  

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

或完全不同的东西。

高度赞赏任何指针。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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