Могу ли я повторно использовать экземпляр output_field в Django ORM или я всегда должен создавать дубликат?

У меня есть кодовая база Django, которая делает много функций Case/When/ExpressionWrapper/Coalesce/Cast ORM, и некоторым из них иногда требуется поле в качестве аргумента - output_field.

from django.db.models import FloatField, F
some_param1=Sum(F('one_value')*F('second_value'), output_field=FloatField())
some_param2=Sum(F('one_value')*F('second_value'), output_field=FloatField())
some_param3=Sum(F('one_value')*F('second_value'), output_field=FloatField())
some_param4=Sum(F('one_value')*F('second_value'), output_field=FloatField())
some_param5=Sum(F('one_value')*F('second_value'), output_field=FloatField())

Иногда я задаюсь вопросом, почему я всегда создаю один и тот же экземпляр любого подкласса Field снова и снова. Есть ли разница, если я просто передаю один экземпляр и разделяю его между выражениями? F.E

from django.db.models import FloatField, F

float_field = FloatField()

some_param1=Sum(F('one_value')*F('second_value'), output_field=float_field)
some_param2=Sum(F('one_value')*F('second_value'), output_field=float_field)
some_param3=Sum(F('one_value')*F('second_value'), output_field=float_field)
some_param4=Sum(F('one_value')*F('second_value'), output_field=float_field)
some_param5=Sum(F('one_value')*F('second_value'), output_field=float_field)

Я не смог найти его в документации, и исходный код не очень хорошо документирован относительно этого параметра.

P.S. Пример ненастоящий, просто представьте себе большую аннотативную функцию, которая делает много обработки с помощью Case/When/ExpressionWrapper/Coalesce/Cast и имеет много дублированных экземпляров Field в качестве output_field.

You can reuse the field. Using this output_field=… [Django-doc] serves two purposes:

  1. тип иногда требует специфического форматирования, обычно для колонок ГИС, поскольку точка, полигон и т.д. должны быть преобразованы в текст, чтобы Django мог их понять; и
  2. для того, чтобы знать, какие преобразования поиска и т.д. могут быть применены к нему.

Действительно, если мы используем:

queryset = queryset.annotate(
    some_param1=Sum(
        F('one_value') * F('second_value'), output_field=CharField()
    )
)

то Django предположит, что some_param1 является CharField (здесь это не имеет большого смысла), и поэтому вы можете использовать:

queryset.filter(some_param1__lower='a')

, поскольку __lower определяется как поиск на CharField. Но для FloatField это не имеет особого смысла.

Но поле не специализировано и не изменяется. Таким образом, это скорее «сигнальный» объект, указывающий, что с ним можно делать.

При этом я не вижу особых причин преобразовывать код, чтобы предотвратить построение FloatField. Если мы используем %timeit, то получим:

In [1]: %timeit FloatField()
3.82 µs ± 379 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

Таким образом, построение занимает примерно 3,82 микросекунды. Обычно представление выполняет гораздо больше работы, поэтому написание запроса, который сам по себе более эффективен, или экономия времени на обход базы данных (очень) вероятно превзойдут любую оптимизацию в отношении экономии FloatField на несколько величин.

Вернуться на верх