2016-02-12 86 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