问题
I am just learning the geo-django. I can find out the distance of all places from a point. But when I use .values
method to the annotated distance
field, I am getting
TypeError: Object of type 'Distance' is not JSON serializable
Here is my code snippets
#models.py
import uuid
from django.contrib.gis.db import models
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.geos import Point
class PlaceManager(models.GeoManager):
def get_queryset(self):
qs = super(PlaceManager, self).get_queryset()
qs = qs.annotate(
latitude=models.ExpressionWrapper(models.Func('position', function='ST_X'), output_field=models.FloatField()),
longitude=models.ExpressionWrapper(models.Func('position', function='ST_Y'), output_field=models.FloatField()),
)
return qs.distinct()
def nearby_places(self, lat, lng):
p = Point(lat, lng, srid=4326)
qs = self.get_queryset()
qs = qs.annotate(
distance=Distance('position', p)
)
return qs.order_by('distance').distinct()
class Place(models.Model):
id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, db_index=True)
position = models.PointField()
address = models.TextField(default=None, null=True, blank=True)
objects = PlaceManager()
def __str__(self):
return '{},{}'.format(self.position.x, self.position.y)
Now the code snippets I have is like this
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
class NearbyPlaces(APIView):
def get(self, request):
p = Place.objects.nearby_places(30.45, -90.43)
p = p.values('distance', 'address', 'latitude', 'longitude')
return Response(p, status=status.HTTP_200_OK)
The value of p
here is like this
<GeoQuerySet [{'distance': Distance(m=7596021.71574835), 'address': 'New York City, New York','latitude': 13.4586, 'longitude': 45.6789}]>
So all I needed here is 'distance': 7596021.71574835
instead of 'distance': Distance(m=7596021.71574835)
Any help on this? Thanks in advance.
回答1:
there is a more simple way, only need to change content in serializer.py:
class CitySerializer(serializers.ModelSerializer):
distance = serializers.SerializerMethodField()
def get_distance(self, obj):
return obj.distance.m
class Meta:
model = City
fields = ('distance')
回答2:
Just Found a way to do it.
Had to make a Renderer class in rest framework and handled the Distance
objects in there. Code snippets are like this.
encoders.py
from rest_framework.utils.encoders import JSONEncoder
from django.contrib.gis.measure import Distance
class CustomJsonEncoderWithDistance(JSONEncoder):
def default(self, obj):
if isinstance(obj, Distance):
print(obj)
return obj.m
return super(CustomJsonEncoderWithDistance, self).default(obj)
renders.py
from rest_framework.renderers import JSONRenderer
from .encoders import CustomJsonEncoderWithDistance
class CustomJsonRenderer(JSONRenderer):
encoder_class = CustomJsonEncoderWithDistance
settings.py
...
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'app.renderers.CustomJsonRenderer',
)
}
来源:https://stackoverflow.com/questions/45376994/geodjango-distance-object-is-not-serializable