#29786: Add option to lock rows with select_for_update() immediately
-------------------------------------+-------------------------------------
Reporter: | Owner: nobody
ovalseven8 |
Type: New | Status: new
feature |
Component: Database | Version: 2.1
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
In my web application I usually follow the "fat models, lightweight views"
philosophy.
To put it in a nutshell, I have two models in my app called "Event" and
"Registration (for Event)":
{{{
class Event(models.Model):
capacity = models.PositiveSmallIntegerField()
def get_number_of_registered_tickets():
return
EventRegistration.objects.filter(event__exact=self).aggregate(total=Coalesce(Sum('number_tickets'),
0))['total']
def reserve_tickets(self, number_tickets):
Event.objects.filter(id=self.id).select_for_update()
if self.get_number_of_registered_tickets() + number_tickets <=
self.capacity:
# create EventRegistration
else:
# handle error
class EventRegistration(models.Model):
time = models.DateTimeField(auto_now_add=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
number_tickets =
models.PositiveSmallIntegerField(validators=[MinValueValidator(1)])
}}}
Now, let's say for a specific event only one ticket is left and two users
want to buy that ticket concurrently. Under unfortunate circumstances
(when I do not use locking), it would be possible that both get the ticket
and now I have a problem. So, I need to make sure that the registration
for an event happens in sequence. That's the reason why I use
**select_for_update()** in the method `reserve_tickets()` above.
Unfortunately, the row is only locked when the QuerySet is evaluates
what's not the case here. So, I need more or less a "dirty hack" like
printing the queryset or creating a list etc.
While this works, I do not think it's a nice solution. Especially for
locking rows, I think it would be a good think if Django had a
"lock/evaluate immediately" option.
Different ideas how the solution API could look like:
`select_for_update().evaluate()`
`select_for_update(evaluate_immediately=True)`
Of course, there're more possibilities. I think it would be a nice little
feature and lazy evaluation is something you perhaps do not want for
locking.
So my question is if you're open for that, if yes I could look into it.
--
Ticket URL: <https://code.djangoproject.com/ticket/29786>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/053.211b57ae55164b546659ca37cc59cbd7%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.