2016-02-12 92 views
0

我有以下的Django模型:Django的自定义反序列化

class Person(models.Model): 
    name = models.CharField() 
    location = models.PointField() 

我要创建这个模型一个串行器/解串器。然而,JSON对象帽子我收到如下:

{ 
    "userList":[ 
     { 
     "username": "Foo", 
     "lat":40.875736, 
     "lon":8.94382834, 
     }, 
     { 
     "username": "Bar", 
     "lat":40.875736, 
     "lon":8.94382834, 
     }, 
    ] 
} 

串行器

class PersonListSerializer(serializers.PersonSerializer): 
    username = serializers.CharField() 
    lat = serializers.FloatField() 
    lon = serializers.FloatField() 


class PersonSerializer(serializers.ModelSerializer): 
    personList = PersonListSerializer 

    class Meta: 
     model = Person 

是否有可能,而无需创建一个额外的模型创建自定义的串行器/解串器来处理这个结构(PersonList)?

在此先感谢。

+0

你目前的反序列化方式是什么? –

+0

更新了问题。我知道我有什么不行,我有一个想法为什么,但可以想出如何解决它! – nunolourenco

+1

添加了DRF标签,因为现在显然你正在使用restframework(这不是核心django的一部分)。 – dhke

回答

2

嗯,这花了一段时间,这绝对是一个很好的学习经验。

你的问题可以分成两个单独的:

  1. 你需要的字段从表示字典两个独立 领域采取它的价值,同时输出两个不同的值。我在前一个缩减并做了一个定制to_internal_value()
  2. 您需要一个ListSerializer不接受并返回一个列表,而是一个包含实际列表的单个嵌套字段的字典。

你可以做到这一点,而不必接触模型。

class ListDictSerializer(serializers.ListSerializer): 
    def get_field_name(self): 
     if not hasattr(self.Meta, 'field_name'): 
      raise ValueError('ListDictSerializer requires defining Meta.field_name overriding get_field_name()') 
     return self.Meta.field_name 

    def to_internal_value(self, data): 
     field_name = self.get_field_name() 
     return super(ListDictSerializer, self).to_internal_value(data[field_name]) 

    def to_representation(self, data): 
     field_name = self.get_field_name() 
     return ReturnDict({ 
       field_name: super(ListDictSerializer, self).to_representation(data) 
      }, serializer=self 
     ) 

    @property 
    def data(self): 
     # skip over the ListSerializer to get the real data without the 
     # ReturnList 
     ret = super(serializers.ListSerializer, self).data 
     return ReturnDict(ret, serializer=self) 


class PersonListSerializer(ListDictSerializer): 
    class Meta: 
     field_name = 'userList' 


class PersonSerializer(serializers.ModelSerializer): 
    class Meta: 
     list_serializer_class = PersonListSerializer 
     model = Person 
     fields = ('username', 'lat', 'lon') 

    username = serializers.CharField(source='name') 
    lat = serializers.SerializerMethodField(method_name='get_latitude') 
    lon = serializers.SerializerMethodField(method_name='get_longitude') 

    def get_latitude(self, instance): 
     return instance.location.coords[1] 

    def get_longitude(self, instance): 
     return instance.location.coords[0] 

    def to_internal_value(self, data): 
     return ReturnDict({ 
      'name': data.get('username'), 
      'location': Point(data['lat'], data['lon']), 
     }, serializer=self) 

请注意,DRF允许您导出任意模型属性(不仅字段)读/写。也就是说,我们可以通过在适当的getter和setter上定义模型@propertylatlon。然而,像Point这样的地理对象在创建后是不可变的,因此您不能在现有对象上选择性地设置单个坐标。

+0

非常感谢!就是这样! =) – nunolourenco