For our blogging platform, we have an “Article” model, that contains an “updated” datetime field:
class Article(models.Model):
updated = models.DateTimeField(null=True, blank=True)
...
When an article gets opened by any visitor for the first time in 24 hours, we do some time consuming calculations on different model fields, subsequently saving the model to the database. With this, we also update our “updated” field to the current datetime.now().
if (datetime.now() - article.updated).days > 1:
# do some time consuming calculations
article.updated = datetime.now()
article.save()
When an article is requested more or less simultaneously, the time consuming operations on the first request have not finished, yet, causing the once-per-day operation to start again on the same object (article.updated has still the old value). May it help calling article.save() additionally right before starting the calculations? Or it this data postponed from saving to the database until the request has finished?
Use the queryset select_for_update introduced in Django 1.4 which does a row level locking in the database. All matched entries will be locked until the end of the transaction block, meaning that other transactions will be prevented from changing or acquiring locks on them. There are a few gotchas specific to datgabase backend so make sure to read up and test it before relying totally on it.
Some other ways to do it independent of the implementation is by customizing your models to have a
lockedboolean attribute. Not very neat but a workable solution. See What is the simplest way to lock an object in Django