Search code examples
pythondjangogispostgisgeodjango

Django get coordinate values of PointField


I want to get x and y coordinates from the point in the following queryset:

user = User.objects.values('id', 'email', 'username', 'point').first()

These are my models:

from django.db.models import Model

from django.contrib.gis.db.models import PointField

class BasePointModel(Model):

    point = PointField(null=True, spatial_index=True, geography=True)

    class Meta:
        abstract = True

class User(AbstractUser, BasePointModel, HashableModel):  # type: ignore

    # First Name and Last Name do not cover name patterns
    # around the globe.
    name = CharField(_("Name of User"), blank=True, max_length=255)
    is_online = BooleanField(_("Is online"), default=False)

I am getting the following result:

{'id': 85270,
 'email': '[email protected]',
 'username': 'username_0',
 'point': <Point object at 0x7f8e061cc2b8>}

How can I get an x and y, making a queryset with values?

I want to get something like this:

{'id': 85270,
 'email': '[email protected]',
 'username': 'username_0',
 'point__x': '-4.266398314110177',
 'point__y': '-39.39432682357033'}

I make requests that return 50,000 lines from a database, and I notice that performance is getting worse due to data serialization. I want to minimize serialization by returning values.

But the PointField always returns an object, and I still haven't found a way to serialize it in the best way.


Solution

  • Tough luck :/
    You are setting the points as geography and therefore you cannot use a custom GeoFunc in order to apply PostGIS's ST_X and ST_Y in an annotation query because they will only work on geometry fields.

    In order to get the [lat, long] values of those points in the values results of the query we can annotate the query with the GeoJSON representation of the points and get those as values. To do that we will use the AsGeoJSON database function:

    user = User.objects.annotate(
        point_as_json=AsGeoJSON('point')
    ).values('id', 'email', 'username', 'point_as_json').first()
    

    which will give us the following result:

    {
      'id': 85270,
      'email': '[email protected]',
      'username': 'username_0',
      'point_as_json': {
        'type': 'Point',
        'coordinates': [-4.26639831, -39.39432682]
       }
    }
    

    As a side note, you can consider augmenting Django with django-rest-framework` and use django-rest-framework-gis on top of that which has some very handy tricks on serialization according to GeoJSON standards.