TypeError: float() argument must be a string or a real number, not 'F'

Hi everyone, Is it possible to change type of F into float or can we get actual value in annotate() ?

from geopy.distance import distance
queryset.annotate(
                distance=distance(
                                   (latitude, longitude), 
                                   (F("address__latitude"), F("address__longitude"))
                                )
            ).filter(distance__lte=query_distance)

In this code I am filtering objects by distance, so distance is a method from geopy that accepts two tuple with lat1, long2 and long1, long2. However my second tuple got F()

Please post the full error message.

Is this a Django error or a database error?

Are you sure it’s the tuple that is incorrect? What is query_distance?

Is the distance function a database function? (Does it translate to SQL, or is it a python-based function?) If it’s a python function, then it can’t be used in the annotation clause.

from geopy.distance import distance
from django_filters import rest_framework as filters

class TaskFilter(filters.FilterSet):
    min_price = filters.NumberFilter(field_name="budget", lookup_expr="gte")
    point = filters.CharFilter(method="filter_by_distance")

    class Meta:
        model = Task
        fields = ["point", "min_price"]

    def filter_by_distance(self, queryset, name, value):
        point = value.split(",")
        if len(point) == 2:
            latitude = float(point[0])
            longitude = float(point[1])
            query_distance = self.data.get("distance")
            queryset = queryset.annotate(
                distance=distance((latitude, longitude), (F("address__latitude"), F("address__longitude")))
            ).filter(distance__lte=query_distance)
        return queryset

No, it’s python-based method that comes from geopy package to calculate distance

Yes, Because distance accepts float or real number type objects.

Is there any way to make it work ?

No. (At least not directly)

The ORM works by creating an SQL statement that gets shipped off to the database, where it is parsed and executed.

The entire statement must rely upon functions available to the database engine. You can’t mix functions between what’s in the database and what only exists in your application.

What you would need to look for would be the equivalent PostGIS function to perform that calculation, or, create your own User-Defined Function to implement it.

There is an answer for this question like mine but I didn’t get it what about it and what user offers to do. Can you check it out ?

Different issue, and not relevant here. Your root issue is that you’re trying to use a Python function in an sql statement. The “float” error is a symptom of the deeper problem. You’re trying to pass an F function to a python function that has no idea of what to do with it.

So is it impossible to extract that actual field value to pass it to python function in annotate?

Looking at this particular expression:

This portion of it on the right-hand side of the assignment operator:

distance(
  (latitude, longitude), 
  (F("address__latitude"), F("address__longitude"))
)

is going to be evaluated before it is constructed into an SQL statement and sent to the database. There is no field address__latitude to retrieve at this point in time, because the processing is still occurring in your application.

Logically, it’s no different than the expression:

Where query_distance (the right-hand side of the assignment operation) is evaluated before the query is sent to the database.

1 Like