можем ли мы изменить значение в наборе запросов django, используя выражение Django «F». Оптимизация запросов

#django-2.0

#django-2.0

Вопрос:

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

Я хочу добавить логику, подобную приведенной выше, в запрос Django.
по сути, я хочу вычислить «возраст», который является причиной необходимости выполнения операции ORM.
наличие больших данных и их время, если я выполняю эту операцию с помощью цикла for.

Ответ №1:

Сначала определите a 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, connection,
            template="EXTRACT(EPOCH FROM %(expressions)s)",
            **extra_context)

    def as_mysql(self, compiler, connection, **extra_context):
        return super().as_sql(
            compiler, connection,
            template="UNIX_TIMESTAMP(%(expressions)s)",
            **extra_context)

    def as_sqlite(self, compiler, connection, **extra_context):
        return super().as_sql(
            compiler, connection,
            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
)
 

Комментарии:

1. Я использую mysql

2. as_mysql используется для MySQL