2017-07-28 43 views
1

我只是在學習geo-django。我可以從一個點找出所有地方的距離。但是當我使用.values方法的註釋distance場,我得到GeoDjango:距離對象不可序列化

TypeError: Object of type 'Distance' is not JSON serializable

這裏是我的代碼片段

#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) 

現在代碼片斷我是這樣

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) 

這裏的價值p就是這樣的

<GeoQuerySet [{'distance': Distance(m=7596021.71574835), 'address': 'New York City, New York','latitude': 13.4586, 'longitude': 45.6789}]> 

因此,所有我需要的是在這裏,而不是'distance': 7596021.71574835'distance': Distance(m=7596021.71574835)

任何幫助?提前致謝。

+0

我建議不使用.values(),而是使用一個串行器。這樣,當serialiser獲取查詢集時,您可以選取距離值並將其設置爲值。 http://www.django-rest-framework.org/tutorial/1-serialization/#creating-a-serializer-class –

+0

那麼找到了另一種方式來做到這一點。只需製作一個渲染器,並將其用作'django rest框架中的默認渲染器類。「# –

+0

在**#models.py **中,只需將** distance = Distance('position',p)**更改爲** distance =距離('位置',p).m **,這將起作用。這樣,您可以保留所有其他代碼原來的**,而無需使用Renderer類。 –

回答

1

剛剛找到一種方法來做到這一點。 不得不在rest框架中創建一個Renderer類,並在那裏處理Distance對象。代碼片段是這樣的。

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', 
    ) 
}