Use QuerySet.select_for_update()
in views to fix race condition
#7751
Replies: 16 comments 1 reply
-
See the discussion taking place on the core django bug tracker: https://code.djangoproject.com/ticket/27477 A similar issue exists in the django admin and class-based generic views. |
Beta Was this translation helpful? Give feedback.
-
Any news? Taking a look at the django bug linked by @etianen I belive we can achieve the solution in the same way:
In my opinion 2 or 3 is the correct approach. I can do a pull request implementing any of these solutions. Do people have a preference or onother approach? |
Beta Was this translation helpful? Give feedback.
-
@mcanaves I'd say we have to consider this as "On-Hold". There's been no progress on the upstream issue and I'm very much inclined to see what the answer is there before implementing something possibly different here. In the meantime I'd advise implementing your own UpdateMixin if this is an actual issue for you. |
Beta Was this translation helpful? Give feedback.
-
I'm not going to close this but I am un-milestoning for now. |
Beta Was this translation helpful? Give feedback.
-
@mcanaves If you're keen to contribute on this, I think the best approach would be to champion the Django issue. Looks like it needs a discussion on Django-Dev. These things always benefit from someone being prepared to Hustle. 🙂 |
Beta Was this translation helpful? Give feedback.
-
@mcanaves I originally raised this issue, plus the one on Django, but ran out of time to push it to completion. Please do continue the efforts in my place, if it's important to you. :) |
Beta Was this translation helpful? Give feedback.
-
I'm not against us resolving this for REST framework's generic views, even if the same issue persists in Django's generic views. I'm not even that fussed about making it a setting if it goes into a major point release, and the behavior is clearly documented. (We can/could suggest eg. a mixin class for backward compatibility concerns, or else have call What it would need at this point is:
|
Beta Was this translation helpful? Give feedback.
-
See also #2648. |
Beta Was this translation helpful? Give feedback.
-
And #5674 |
Beta Was this translation helpful? Give feedback.
-
We have been bitten hard by this, @jarekwg has a fixed this inline but it would be great to not have to do this on every endpoint by moving the solution into DRF. |
Beta Was this translation helpful? Give feedback.
-
Looking forward a PR to review it. |
Beta Was this translation helpful? Give feedback.
-
Heh yep, I overrode the
Simply put, the fix means we lose out on the niceness I like the the suggestion mentioned somewhere earlier with passing e: Found a slightly nicer implementation, though would still be nicer in DRF itself..:
|
Beta Was this translation helpful? Give feedback.
-
@jarekwg using the update_fields parameter has been suggested multiple times. #2648 #5674 select_for_update is a more heavy weight approach that would eliminate the need for update_fields. In my case however the race condition was with different users whose updates could only be disjoint sets so update_fields was the ideal solution to resolve the race condition without incurring the overhead of locking the database row. I don't really see the downside of always utilizing update_fields and while I'm not super familiar with Django's ORM layer I'd assume if anything it'd be a slight performance improvement. As a heavy user of this wonderful framework, my own 2p regarding these issues:
These issues aren't hard to workaround for end users, but it does take some digging around in the source code to figure out the best approach to implement them. So at least some documentation on the best solution from the perspective of the DRF authors might be in order. |
Beta Was this translation helpful? Give feedback.
-
A PATCH/partial update should only update the fields it touches by default, and The suggestion around |
Beta Was this translation helpful? Give feedback.
-
As pointed by @litchfield and in #5897, adding the update_fields to save would prevent many of this problems. Quoting @tleewu from #5897 :
|
Beta Was this translation helpful? Give feedback.
-
Why not write your own ModelViewSet if you still wanna use select_for_update for PUT and PATCH?
Eg. usage
PS: I have set |
Beta Was this translation helpful? Give feedback.
-
There is a race condition in PUT and PATCH operations where a user can edit a model instance at the same time as another user. Consider the following two operations occurring in parallel:
{"is_staff": True}
User.objects.update(is_superuser=True)
If (1) load the model instance, then (2) runs, then (1) saves the model instance, the update in (2) will be lost.
The solution is to call
select_for_update
on the queryset in theupdate()
method ofUpdateModelMixin
.Checklist
master
branch of Django REST framework.Beta Was this translation helpful? Give feedback.
All reactions