transaction.atomic() rolls back if another query is executed

39 Views Asked by At

I am having issues with Django's transaction.atomic. I have this app that users can update their information, but I will be giving an example here using age, but in reality it will be something like an account balance.

So I want to prevent update to this field if more than one requests is received concurrently, so I want to lock the row which is why I am using transaction.atomic and select_for_update. So I have a UserProfile model that I want to update some information, the method which i use to update is below:

Class Profile(models.Model):
    def get_queryset(self):
        return self.__class__.objects.filter(id=self.id)

    @transaction.atomic()
    def update_age(
        self,
        age: int,
    ) -> None:
        obj = self.get_queryset().select_for_update().get()
        obj.age = age
        obj.save()

Below is the view

class UserProfileView(APIView):
    
    def put(self, request):
        profile = rquest.user.profile
        profile.update_age(request.data["age"])
    
        UpdateHistory.objects.create(user=request.user, updated_field="age")

The issue is UpdateHistory object is created but the age update is rolled back, but when I remove the creation of the UpdateHistory, the age is updated successfully. So the above code only creates UpdateHistory, but doesn’t update UserProfile.age. But if I remove the line UpdateHistory.objects.create(user=request.user, updated_field="age"), the age is updated successfully.

No exception is being raised at all, this has been confusing me for days. Hopefully I can get some help. Thanks in advance

1

There are 1 best solutions below

1
2ps On

I would have just used a django update:

self.get_queryset().update(age=age)