2

I have a Django codebase that does a lot of Case/When/ExpressionWrapper/Coalesce/Cast ORM functions and some of them sometimes need a field as an argument - 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())

Sometimes I find myself wondering why am I always creating the same instance of any Field subclass over and over again. Is there any difference if I just pass one instance and share it between expressions? 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)

I coulnd't find it in a documentation and the source code is not documented well regarding this parameter.

P.S. The example is fake, just imagine a big annotate function that does a lot of processing using Case/When/ExpressionWrapper/Coalesce/Cast and has a lot of duplicated Field instances as output_field.

4
  • 1
    you can use the same one, since it is more used for its SQL type, and for lookups. But I don't really see any added value converting the first one in the second: constructing a FloatField runs in microseconds. Commented Oct 23, 2024 at 11:35
  • I understand that, but when it's used around 30-40 times in ONE annotate i think if it can speed up the code execution even for a little bit it would be nice. the code needs to be refactored I know but for now I am trying to speed it up at least a little. Commented Oct 23, 2024 at 11:39
  • 1
    I doubt that, because typically the largest overhead is sending the query to the database, and retrieving the data. Typically this takes magnitudes more time. Commented Oct 23, 2024 at 11:40
  • 1
    with %timeit FloatField() it says "3.82 µs ± 379 ns per loop", so that would be at most 160 microseconds. Likely it is more code caching: if you run a program a second time, the bytecode is still in the cache, so the calls itself work faster, you always need to test program 1 and then program 2, and then the reverse. Commented Oct 23, 2024 at 11:50

1 Answer 1

1

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

  1. the type sometimes requires specific formatting, typically for GIS columns, since a point, polygon, etc. needs to be converted to text so that Django can understand it; and
  2. to know what lookups transformations, etc. can be applied on it.

Indeed, if we use:

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

then Django will assume that some_param1 is a CharField (here this does not make much sense), and thus you can use:

queryset.filter(some_param1__lower='a')

since __lower is defined as a lookup on a CharField. But for a FloatField, it does not make much sense.

But the field is not specialized or altered. It is thus more of a "signal" object to specify what can be done with it.

That being said, I don't see much reasons to convert code to prevent constructing a FloatField. If we use %timeit, we get:

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

So the construction takes approximately 3.82 microseconds. Typically a view has a lot more work to do than that, so writing a query that is itself more efficient, or saving a roundtrip to the database, will (very) likely outperform any optimization with respect to saving a FloatField by a few magnitudes.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.