【问题标题】:Django REST Framework: nested relationship, how to submit json?Django REST Framework:嵌套关系,如何提交json?
【发布时间】:2019-02-19 18:25:03
【问题描述】:

我正在使用 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 在后端执行操作了。

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    默认情况下,嵌套序列化程序的通用写入不可用。这是有原因的:

    考虑一下,您正在使用POST 请求创建一个有出生地的人。目前尚不清楚提交的城市是新城市还是现有城市。如果没有这样的城市,它应该返回错误吗?还是应该创建?

    这就是为什么,如果你想在你的序列化器中处理这种关系,你需要编写你自己的序列化器的create()update()方法。

    这里是 DRF 文档的相关部分:http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

    【讨论】:

    • > "我不需要在 REST 接口上写任何东西。"我只需要从中检索数据,但我不知道如何将数据提交给序列化程序,以便将它们转换为 dajngo 对象。
    【解决方案2】:

    绝对没有明确地放入 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"
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多