Django过滤查询,自动计算属性字段

bob*_*bsr 11 python django django-models

有Django Order模型,属性字段自动calucated.如何进行过滤查询.

class Order(models.Model):

    @property
    def expire(self):
        return self.created + datetime.timedelta(days=self.days_left())

    @property
    def days_left(self):
        return self.recurrence_period  * self._recurrence_unit_days[self.recurrence_unit]
Run Code Online (Sandbox Code Playgroud)

为了从今天起获得1,3,7个日期时间而进行的计算

settings.SUBSCRIPTION_EXPIRATION_REMIND = [1, 3, 7]

days = map(lambda x: datetime.date.today() + datetime.timedelta(days=x), settings.SUBSCRIPTION_EXPIRATION_REMIND)

[datetime.date(2015, 7, 28),
 datetime.date(2015, 7, 30),
 datetime.date(2015, 8, 3)]
Run Code Online (Sandbox Code Playgroud)

如何通过ORM查询过滤

Order.objects.filter(expire__in=days)
Run Code Online (Sandbox Code Playgroud)

Django正在抛出错误.

FieldError: Cannot resolve keyword 'expire' into field.
Run Code Online (Sandbox Code Playgroud)

Rah*_*pta 31

不,您无法基于模型方法或属性执行查找.Django ORM不允许这样做.

查询被编译为SQL以在数据库级别发送和处理,而属性是Python代码,数据库对它们一无所知.这就是为什么Django过滤器只允许我们使用数据库字段的原因.

可以这样做:

Order.objects.filter(created=..) # valid as 'created' is a model field
Run Code Online (Sandbox Code Playgroud)

不能这样做:

Order.objects.filter(expires=..) # INVALID as 'expires' is a model property
Run Code Online (Sandbox Code Playgroud)

您可以改为使用列表推导来获得所需的结果.

[obj for obj in Order.objects.all() if obj.expire in days]
Run Code Online (Sandbox Code Playgroud)

以上将给出列表中Order具有expire值的对象days列表.

  • 重要的是要注意,通过使用列表推导,您正在强制求值,现在您的数据类型是“列表”,而不是“查询集”。在许多情况下,例如`get_queryset()`方法,这将不起作用。 (2认同)
  • 我将详细说明一下@TaylorEdmiston注释,即遍历QuerySet对象(此处为Order.objects.all())将迫使数据库遍历Order表中所有已存在的记录。由于性能原因,这是完全不可接受的。如果要通过模型的方法或属性查询数据库,可以考虑相应地使它们成为具有数据库索引的模型字段 (2认同)

bob*_*bsr -15

最终将过期添加到模型中,计算保存方法的值。现在我可以做

 Order.objects.filter(expire__in=days)
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个解决方案。 (18认同)