【问题标题】:Django Custom DeserializationDjango 自定义反序列化
【发布时间】:2016-05-23 21:37:03
【问题描述】:

我有以下 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)?

提前致谢。

【问题讨论】:

  • 你目前的反序列化方式是什么?
  • 更新了问题。我知道我所拥有的东西不起作用,我知道为什么,但可以弄清楚如何解决它!
  • 添加了 DRF 标签,因为现在很明显您正在使用 restframework(它不是核心 django 的一部分)。
  • 抱歉,忘记了!谢谢!!!

标签: python json django django-rest-framework


【解决方案1】:

嗯,这需要一段时间,这绝对是一次不错的学习体验。

您的问题可以分为两个独立的问题:

  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 在模型上定义 @property latlon。但是,像Point 这样的地理对象在创建后是不可变的,因此您不能有选择地在现有对象上设置单个坐标。

【讨论】:

  • 非常感谢!就是这样! =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
相关资源
最近更新 更多