我们可以使用 Django "F" 表达式修改 django 查询集中的值吗?查询优化

问题描述

Now = datetime.utcNow().replace(tzinfo=utc)
    
.annotate(
        age=F(int((Now - 'ended_at').total_seconds() / (60 * 60)))

我想在 Django 查询添加上述逻辑。 基本上我想计算“年龄”,这是需要执行操作 ORM 的原因。 如果我使用 for 循环执行此操作,则数据量很大且需要时间。

解决方法

首先定义一个 Func 来提取自 UNIX 纪元以来的秒数。

from django.db.models import Func,IntegerField

class UnixTime (Func):
    """
    Extract the number of seconds since January 1,1970.
    """

    arity = 1
    output_field = IntegerField()

    # for PostgreSQL
    def as_sql(self,compiler,connection,**extra_context):
        return super().as_sql(
            compiler,template="EXTRACT(EPOCH FROM %(expressions)s)",**extra_context)

    def as_mysql(self,template="UNIX_TIMESTAMP(%(expressions)s)",**extra_context)

    def as_sqlite(self,template="CAST(strftime('%%%%s',%(expressions)s) AS INTEGER)",**extra_context)

然后进行这样的查询:

from django.db.models import F
from django.db.models.functions import Now

YourObject.objects.annotate(
    age=(UnixTime(Now()) - UnixTime(F('ended_at'))) / 3600
)