Django的自定义反序列化
问题描述:
我有以下的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)?
在此先感谢。
答
嗯,这花了一段时间,这绝对是一个很好的学习经验。
你的问题可以分成两个单独的:
- 你需要的字段从表示字典两个独立 领域采取它的价值,同时输出两个不同的值。我在前一个缩减并做了一个定制
to_internal_value()
- 您需要一个
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上定义模型@property
lat
和lon
。然而,像Point
这样的地理对象在创建后是不可变的,因此您不能在现有对象上选择性地设置单个坐标。
+0
非常感谢!就是这样! =) – nunolourenco
你目前的反序列化方式是什么? –
更新了问题。我知道我有什么不行,我有一个想法为什么,但可以想出如何解决它! – nunolourenco
添加了DRF标签,因为现在显然你正在使用restframework(这不是核心django的一部分)。 – dhke