Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concurrency control in Django model

Tags:

How do I handle concurrency in a Django model? I don't want the changes to the record being overwritten by another user who reads the same record.

like image 578
Pablo Avatar asked Oct 29 '09 17:10

Pablo


People also ask

How does Django handle concurrency?

In terms of Django, optimistic concurrency control can be implemented by overriding the save method on your model class... And, of course, for either of these concurrency mechanisms to be robust, you have to consider transactional control.

Does Django support concurrency?

django-concurrency works adding a concurrency. fields. VersionField to each model, each time a record is saved the version number changes (the algorithm used depends on the implementation of concurrency.

What is race condition in Django?

Database race condition with tasks and Django request handlers. Data races happen when two or more concurrent threads try to access the same memory address (or in this case, some specific data in a database) at the same time.

What is Django ForeignKey model?

ForeignKey is a Django ORM field-to-column mapping for creating and working with relationships between tables in relational databases. ForeignKey is defined within the django. db. models. related module but is typically referenced from django.


2 Answers

The short answer, this really isn't a Django question as presented.

Concurrency control is often presented as a technical question, but is in many ways a question of functional requirements. How do you want/need your application to work? Until we know that, it will be difficult to give any Django-specific advice.

But, I feel like rambling, so here goes...

There are two questions that I tend to ask myself when confronted with the need for concurrency control:

  • How likely is it that two users will need to concurrently modify the same record?
  • What is the impact to the user if his/her modifications to a record are lost?

If the likelihood of collisions is relatively high, or the impact of losing a modification is severe, then you may be looking at some form of pessimistic locking. In a pessimistic scheme, each user must acquire a logical lock prior to opening the record for modification.

Pessimistic locking comes with much complexity. You must synchronize access to the locks, consider fault tolerance, lock expiration, can locks be overridden by super users, can users see who has the lock, so on and so on.

In Django, this could be implemented with a separate Lock model or some kind of 'lock user' foreign key on the locked record. Using a lock table gives you a bit more flexibility in terms of storing when the lock was acquired, user, notes, etc. If you need a generic lock table that can be used to lock any kind of record, then take a look at the django.contrib.contenttypes framework, but quickly this can devolve into abstraction astronaut syndrome.

If collisions are unlikely or lost modifications are trivially recreated, then you can functionally get away with optimistic concurrency techniques. This technique is simple and easier to implement. Essentially, you just keep track of a version number or modification time stamp and reject any modifications that you detect as out of whack.

From a functional design standpoint, you only have to consider how these concurrent modification errors are presented to your users.

In terms of Django, optimistic concurrency control can be implemented by overriding the save method on your model class...

def save(self, *args, **kwargs):     if self.version != self.read_current_version():         raise ConcurrentModificationError('Ooops!!!!')     super(MyModel, self).save(*args, **kwargs) 

And, of course, for either of these concurrency mechanisms to be robust, you have to consider transactional control. Neither of these models are fully workable if you can't guarantee ACID properties of your transactions.

like image 78
Joe Holloway Avatar answered Nov 03 '22 02:11

Joe Holloway


I don't think that 'keeping a version number or timestamp' works.

When self.version == self.read_current_version() is True, there is still a chance that the version number got modified by other sessions just before you call super().save().

like image 27
ivan Avatar answered Nov 03 '22 03:11

ivan