自定义管理器并不总是为多对一关系添加计算字段
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
应该有一个计算字段(一个称为 delta
的 timedelta
),显示它发生在前一个事件之后的时间。因为 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.delta
或events.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
您也可以使用此方法在模板中进行排序。
另一种方法是在视图中添加您需要的任何计算字段(但同样,您需要注意在模板中访问时不修改查询集,否则会发出新查询,对象将被重新实例化,您在视图中添加的任何字段都将丢失。
我正在为一个项目使用 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
应该有一个计算字段(一个称为 delta
的 timedelta
),显示它发生在前一个事件之后的时间。因为 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.delta
或events.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
您也可以使用此方法在模板中进行排序。
另一种方法是在视图中添加您需要的任何计算字段(但同样,您需要注意在模板中访问时不修改查询集,否则会发出新查询,对象将被重新实例化,您在视图中添加的任何字段都将丢失。