Home > Software design >  Update many objects in one query DRF
Update many objects in one query DRF

Time:02-20

I need to bulk update ("is_read" = True) Message instanses by given list of ids in one request with this code:

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

Model:

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"))

I have this serializer:

class MessageIsReadSerializer(serializers.ModelSerializer):

    class Meta:

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

And method in 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()),
]

But as a result of running this query I get an error:

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'.

What is wrong?

With help of Bartosz Stasiak I've fixed my verion of put method.

    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)

CodePudding user response:

First: here you are getting a queryset, not an instance, so later in your code you are appending querysets to the instances list. If you want to access single instance you should use get instead of filter

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

If you want to update multiple items you can use:

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)
  • Related