How to make calculation inside django annotate?

Question:

This one when I run generates error:

qs = UserLocation.objects.annotate(distance=0.5 - cos((F('lat')-lat1)*p)/2 + cos(lat1*p) * cos(F('lat')*p) * (1-cos((F('long')-lon1)*p))/2).all()

The error it generates is this one:

must be real number, not CombinedExpression

How can I make that calculation as an annotation

Asked By: rev-kid

||

Answers:

Try adding ExpressionWrapper as described here:
https://docs.djangoproject.com/en/3.2/ref/models/expressions/#using-f-with-annotations

qs = UserLocation.objects.annotate(distance=ExpressionWrapper(0.5 - cos((F('lat')-lat1)*p)/2 + cos(lat1*p) * cos(F('lat')*p) * (1-cos((F('long')-lon1)*p))/2).all(), output_field=FloatField())

I might missed some ) because your calculation is complicated and I assumed that result is a float

Answered By: Bartosz Stasiak

I think you need to use Django’s Cos database function when finding the cosine of a value which involves an F() expression.

Python’s math.cos function seems to produce the must be real number error when used with an F() expression.

To take a simple example, this produces the must be real number error:

from math import cos

...

Vector.objects.annotate(x_cos=cos(F('x') + 1))

But this seems to work:

from django.db.models.functions import Cos

...

Vector.objects.annotate(x_cos=Cos(F('x') + 1))

So to take your example, I think you’ll want something like this:

from math import cos
from django.db.models.functions import Cos

...

qs = UserLocation.objects.annotate(distance=0.5 - Cos((F('lat')-lat1)*p)/2 + cos(lat1*p) * Cos(F('lat')*p) * (1-Cos((F('long')-lon1)*p))/2)
Answered By: countermeasure