【问题标题】:Update objects with DRF Serializer with data from JSON使用来自 JSON 的数据使用 DRF 序列化程序更新对象
【发布时间】:2018-05-03 10:37:08
【问题描述】:

我得到一个包含来自多个对象的数据的 JSON 响应,通过序列化程序运行所有内容并调用 serializer.save(),它会创建新对象但不会更新现有对象。

查看

data = JSONParser().parse(request)
serializer = CellCESaveSerializer(data=data, many = True, context = {'descriptoridlist' : descriptoridlist}, partial=True)
if serializer.is_valid():
    serializer.save()
    return JsonResponse(serializer.data, safe=False)

序列化器

class StringArrayField(ListField):
    """
    String representation of an array field.
    """
    def to_representation(self, obj):
        obj = super().to_representation(obj)
        # convert list to string
        return ",".join([str(element) for element in obj])

    def to_internal_value(self, data):
        data = data.rstrip(",")  # Needed because of JSON response
        data = data.split(",")  # Split string to list
        data = [int(i) for i in data] # convert str to int
        did = self.context['descriptoridlist']
        x = (did,data)   # Create Array
        return super().to_internal_value(x)

class CellCESaveSerializer(serializers.ModelSerializer):
    row = serializers.SlugRelatedField(slug_field="name",queryset=Descriptor.objects.all() ) # foreignkey mit namen
    val = StringArrayField()   

    class Meta:
        model = CellCE
        fields = ('row','val')

如何在不创建新对象的情况下更新现有对象?

编辑 1:

添加@neverwalkaloner 更改后,我意识到我需要使用 ListSerializer 来更新多个对象。我在DRF documentation 的帮助下调整了我的代码。 (我把序列化器改成了 ListSerializer,添加了 id 字段和更新方法。)

序列化器:

class CellCESaveSerializer(serializers.ListSerializer):
    row = serializers.SlugRelatedField(slug_field="name",queryset=Descriptor.objects.all()) # foreignkey mit namen
    val = StringArrayField()
    id = serializers.IntegerField()


    class Meta:
        model = CellCE
        fields = ('row','val')

    def update(self, instance, validated_data):
        CellCE_mapping = {CellCE.id: CellCE for CellCE in instance}
        data_mapping = {item['id']: item for item in validated_data}

        # Perform creations and updates.
        ret = []
        for CellCE_id, data in data_mapping.items():
            CellCE = CellCE_mapping.get(CellCE_id, None)
            if CellCE is None:
                ret.append(self.child.create(data))
            else:
                ret.append(self.child.update(CellCE, data))

        # Perform deletions.
        for CellCE_id, CellCE in CellCE_mapping.items():
            if CellCE_id not in data_mapping:
                CellCE.delete()

        return ret

我得到错误:

AssertionError: `child` is a required argument.

我错过了什么?

【问题讨论】:

    标签: django serialization django-rest-framework


    【解决方案1】:

    序列化器的save() 方法检查序列化器的self.instance 是否为空。如果self.instance为空save()会调用create()方法,否则调用update()方法。

    所以要使用序列化程序更新实例,您需要将其作为更新对象的第一个参数传递:

    obj = CellCE.objects.get(id='some_id') # Object wich will be updated
    serializer = CellCESaveSerializer(obj, data=data, many = True, context = {'descriptoridlist' : descriptoridlist}, partial=True)
    if serializer.is_valid():
        serializer.save()
        return JsonResponse(serializer.data, safe=False)
    

    【讨论】:

      【解决方案2】:

      不需要使用 ListSerializer,因为当你传递“many=True”时,它也使用 ListSerializer 类。如果您想更新一次对象,请包含“id”字段并将其值传递到输入数据中。

      【讨论】:

      • 如果我使用serializer.ModelSerializer 类,我会得到NotImplementedError: Serializers with many=True do not support multiple update b y default, only multiple create. For updates it is unclear how to deal with inse rtions and deletions. If you need to support multiple update, use a ListSeriali zer class and override .update() so you can specify the behavior exactly.
      • 是的,所以如果你使用这个序列化器更新多个,只需覆盖序列化器的更新功能。或者,如果您使用 ListSerialier,它需要传递“child”属性。它是一个序列化器类,将用于更新每个项目。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多