6

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': 'username_0@email.com',
 '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': 'username_0@email.com',
 '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.

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
Narnik Gamarnik
  • 1,049
  • 1
  • 16
  • 35

3 Answers3

2

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': 'username_0@email.com',
  '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.

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
0

You could access the __dict__ method of your object and then directly with your geometry:

user = User.objects.values('id', 'email', 'username', 'point').first()
user_dict = user.__dict__
user_dict.update({'point__x':user_dict['point'].x, {'point__y':user_dict['point'].y})
tgrandje
  • 2,332
  • 11
  • 33
0

The best way to get what you need is through a Serializer like the one bellow.

class LayerGeometrySerializer(GeoFeatureModelSerializer):
    """
    GeoFeatureModelSerializer is a subclass of rest_framework.ModelSerializer which will output data in a format that is GeoJSON compatible
    """
    values = LayerValueMinimalSerializer(source='layervalue_set', many=True)

    class Meta:
        model = LayerGeometry
        geo_field = 'geom'
        exclude = ('created', 'modified', )