1

在 Django Rest Framework ListSerializer 中,当我想通过调用 instance.save() 将验证数据保存到数据库时,我收到一条错误消息,提示 queryset 对象没有属性 save

ListSerializer 类:

class NoAccessDetailsListSerializer(serializers.ListSerializer):

    # This will be called when there is list of objects
    #here instance is list of queryset and validated_data is the list of json object
    def update(self, instance, validated_data):

        ret = []
        for index, data in enumerate(validated_data):

            #checking if row is already chosen
            if(instance[index].row_chosen):

                # do not update the info to db
                # just append the data to ret
                ret.append(instance[index])

            else:
                instance.id = instance[index].id
                instance.row_chosen = validated_data[index].get(
                    'row_chosen')
                instance.user_working = validated_data[index].get(
                    'user_working')

                ret.append(instance)

                instance.save()

        return ret

序列化器类

class NoAccessDetailsSerializer(serializers.ModelSerializer):


    id = serializers.IntegerField(read_only=False)

    class Meta:
        model = NoAccessDetails
        list_serializer_class = NoAccessDetailsListSerializer
        fields = ("id", "row_chosen",
                  "user_working")

    def update(self, instance, validated_data):
        instance.id = instance.id
        instance.row_chosen = validated_data.get(
            'row_chosen')
        instance.user_working = validated_data.get(
            'user_working ')

        instance.save()
        return instance

基本上在 ListSerializer 中,我正在检查数据库中是否已经选择了该行。如果为True,那么我只需将实例数据附加到字典中,否则我想将数据更新到数据库并将更新的数据附加到列表并返回。

在 ListSerializer 中,我将来自 APIView 类的过滤查询集作为实例传递,并且 valid_data 是经过验证的数据列表。

我将传递给 APIView 类的示例 JSON 数据:

[
        {
            "id": 1,
            "row_chosen": true,
            "user_working": "John"
        },
        {
            "id": 1,
            "row_chosen": true,
            "user_working": "David"
        },
]

当我传递 JSON 数据时,它会正确地从 DB 中过滤掉行并将查询集作为实例和 JSON 数据传递给序列化程序类。

# here list_of_id is the ids which are there in the JSON object. i.e [1,2]

filtered_id_data= NoAccessDetails.objects.filter(
                id__in=list_of_id)

            serializer = NoAccessDetailsSerializer(filtered_id_data,
                                                   data=request.data,
                                                   many=True,
                                                   )

ListSerializer update() 正在工作,但是当它运行 else 块并尝试更新数据时,它给了我一个错误queryset object has no attribute save。而在序列化程序的 update() 中,它运行 instance.save() 并更新单个对象的数据。我不确定我在哪里犯了错误。请帮我解决一下这个。

更新:

我在 ListSerializer 类中将 instance.save() 更改为 instance[index].save() 。现在查询集对象没有属性保存已修复。即使当我使用 instance[index].save() 时,我也无法将数据保存在数据库中。

楷模:

class NoAccessDetails(models.Model):
    20 CharFields
    ...
    ...
    user_working = models.ForeignKey(
        UserProfile, on_delete=models.CASCADE, blank=True, null=True)
    row_chosen = models.BooleanField(default=False)

class UserProfile(models.Model):
    user_id = models.CharField(primary_key=True, max_length=10)
    user_name = models.CharField(max_length=100)
    user_email = models.EmailField()
    is_admin = models.BooleanField(default=False)

在 NoAccessDetail 模型中,我将 user_working null 设置为 true,因为该模型的数据将来自不同的来源。最初在导入数据时 user_working 将为空。从 API 调用更新数据时,我正在验证 JSON 数据。

4

1 回答 1

0

要调用 .save() 方法,您必须在模型的实例上调用它,而不是在模型的 QuerySet 上。根据 DRF Docs,

class BookListSerializer(serializers.ListSerializer):
  def update(self, instance, validated_data):
    # Maps for id->instance and id->data item.
    book_mapping = {book.id: book for book in instance}
    data_mapping = {item['id']: item for item in validated_data}

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

    # Perform deletions.
    for book_id, book in book_mapping.items():
        if book_id not in data_mapping:
            book.delete()

    return ret

您可以看到他们正在使用 book_mapping。这是创建一个字典,其中键是书的 id,值是书的实例。

希望这可以帮助!

编辑 检查'else:'块下方的行。您看到您需要使用 .get() 来获取要更新的模型的对象,然后使用 .save() 方法。

重新编辑 使用 instance[index].save() 也应该有效。我认为您需要在附加到 ret 之前调用 obj.save()。

class NoAccessDetailsListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        ...
        ...
        else:
            obj = NoAccessDetails.objects.get(id=instance[index].id)
            # or obj = instance[index]
            obj.row_chosen = validated_data[index].get(
                'row_chosen')
            obj.user_working = validated_data[index].get(
                'user_working')

            print('Instance data ',
                  obj.row_chosen,
                  obj.user_working)
            obj.save() # call this before appending to ret
            ret.append(obj)


    return ret

重新编辑

我根据文档更新了片段。

class NoAccessDetailsListSerializer(serializers.ListSerializer):

# This will be called when there is list of objects
# here instance is list of queryset and validated_data is the list of json object
def update(self, instance, validated_data):

    ret = []

    obj_mapping = {obj.id: obj for obj in instance}
    data_mapping = {item['id']: item for item in validated_data}

    for obj_id, data in data_mapping.items():
        obj = obj_mapping.get(obj_id, None)
        if not obj:
            continue

        if obj.row_chosen:
            ret.append(obj)
        else:
            obj.row_chosen = data['row_chosen']
            obj.user_working = data['user_working']
            obj.save()
            ret.append(obj)

    return ret
于 2019-09-28T19:48:49.023 回答