在一次查询 DRF 中更新多个对象

Update many objects in one query DRF

我需要使用此代码在一个请求中通过给定的 ID 列表批量更新 ("is_read" = True) 消息实例:

{"ids": [11, 4, 7]}

型号:

class Message(models.Model):

text = models.TextField(max_length=500, verbose_name=_("Text"))
sender = models.ForeignKey(
    to=User,
    on_delete=models.CASCADE,
    related_name="sender_message",
    verbose_name=_("User"),
)
thread = models.ForeignKey(
    to="Thread",
    on_delete=models.CASCADE,
    related_name="thread_message",
    verbose_name=_("Thread"),
)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
is_read = models.BooleanField(default=False, verbose_name=_("Is read"))

我有这个序列化程序:

class MessageIsReadSerializer(serializers.ModelSerializer):

    class Meta:

        model = Message
        fields = ("id", "text", "sender", "is_read")

和views.py中的方法:

class MessageIsRead(APIView):

permission_classes = (AllowAny,)
queryset = Message.objects.all()

def put(self, request, *args, **kwargs):
    id_list = request.data['ids']
    instances = []
    for item in id_list:
        obj = self.queryset.filter(id=item)
        obj.is_read = True
        instances.append(obj)
    serializer = MessageIsReadSerializer(instances, many=True)
    return Response(serializer.data)

urls.py

urlpatterns = [
    path("messages-read/", MessageIsRead.as_view()),
]

但是由于 运行 这个查询,我得到一个错误:

AttributeError at /messages-read/
Got AttributeError when attempting to get a value for field `text` on serializer 
`MessageIsReadSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the 
`QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'text'.

怎么了?

Bartosz Stasiak 的帮助下,我修复了 put 方法的版本。

    def put(self, request, *args, **kwargs):
    id_list = request.data['ids']
    instances = []
    for item in id_list:
        obj = self.queryset.get(id=item)
        obj.is_read = True
        obj.save()
        instances.append(obj)
    serializer = MessageIsReadSerializer(instances, many=True)
    return Response(serializer.data)

首先:这里你得到的是一个查询集,而不是一个实例,所以稍后在你的代码中你将查询集附加到 instances 列表。如果你想访问单个实例,你应该使用 get 而不是 filter

single_instance = self.queryset.get(id=item)

如果您想更新多个项目,您可以使用:

def put(self, request, *args, **kwargs):
    id_list = request.data['ids']

    instances = self.queryset.filter(id__in=id_list)
    instances.update(is_read=True)
    
    serializer = MessageIsReadSerializer(instances, many=True)
    return Response(serializer.data)