Django REST Framework:嵌套关系,如何提交json?

时间:2018-09-14 23:53:35

标签: django django-rest-framework

我正在使用Django 2.1,DRF 3.7.7。
我有一些模型及其相对的(模型)序列化器:这些模型是嵌套的,序列化器也是嵌套的。 让我举个例子:

# models.py
class City(models.Model):
    name = models.CharField(max_length=50)

class Person(models.Model):
    surname = models.CharField(max_length=30)
    birth_place = models.ForeignKey(City)


# serializers.py
class CitySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.CitySerializer
        fields = "__all__"

class PersonSerializer(serializers.ModelSerializer):
    birth_place = CitySerializer()

    class Meta:
        model = models.Person
        fields = "__all__"

如果我提交带有json之类的AJAX请求:
{'surname': 'smith', 'birth_place': 42}
我得到一个Bad Request的回复,其中包含:Invalid data. Expected a dictionary, but got int.

如果我提交嵌套的json,例如:
{'surname': 'smith', 'birth_place': {'id': 42, 'name': 'Toronto'}}
关系未转换,id字段将被忽略,其余部分将解析为:
OrderedDict([('birth_place', OrderedDict([('name', 'Toronto')]))])

以下是我在基于类的视图上使用的post方法:

def post(self, request):
    print("Original data:", request.data)
    serializer = self.serializer_class(data=request.data)
    if serializer.is_valid():
        self.data = serializer.validated_data
        print("Parsed data:", self.data)
        ...

我只需要从连接到序列化器的端点获取数据,我不需要通过REST接口写入/保存任何内容,因为表单的POST处理是由Django完成的

TL; DR :如何在不编写手工转换的情况下正确地向嵌套序列化器提交JSON请求?在设置序列化程序时是否犯了错误?

编辑:我发现,通过将id = serializers.IntegerField()添加到序列化程序的父类(例如City),序列化程序解析器现在可以处理ID。至少现在我可以使用django在后端执行操作。

1 个答案:

答案 0 :(得分:1)

django-rest的文档中没有明确地注明它。如果遵循序列化程序处理数据以进行创建的过程,那么很明显django通过先保存父实例然后添加m2m值来管理m2m,但是如果将m2m字段标记为只读。

解决方案是覆盖序列化程序的run_validation方法。序列化器应如下所示:

class ExampleSerializer(serializers.ModelSerializer):
    queryset = SomeModel.objects.all()
    tags = TagSerializer(many=True, read_only=True)

    class Meta:
        model = SomeModel
        fields = ['pk', 'name', 'tags']

    def run_validation(self, data):
        validated_data = super(StudyResourceSerializer, self).run_validation(data)
        validated_data['tags'] = data['tags']
        return validated_data

请求正文应如下所示:

{
    "tags": [51, 54],
    "name": "inheritance is a mess"
}