title: Handling race condition in model.save()
body: <p>How should one handle a possible race condition in a model's <code>save()</code> method?</p>
  
  <p>For example, the following example implements a model with an ordered list of related items. When creating a new Item the current list size is used as its position. </p>
  
  <p>From what I can tell, this can go wrong if multiple Items are created concurrently.</p>
  
  <pre><code>class OrderedList(models.Model):
      # ....
      @property
      def item_count(self):
          return self.item_set.count()
  
  class Item(models.Model):
      # ...
      name   = models.CharField(max_length=100)
      parent = models.ForeignKey(OrderedList)
      position = models.IntegerField()
      class Meta:
          unique_together = (('parent','position'), ('parent', 'name'))
  
      def save(self, *args, **kwargs):
          if not self.id:
              # use item count as next position number
              self.position = parent.item_count
          super(Item, self).save(*args, **kwargs)
  </code></pre>
  
  <p>I've come across <a href="http://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views" rel="noreferrer">@transactions</a><code>.commit_on_success()</code> but that seems to apply only to views. Even if it did apply to model methods, I still wouldn't know how to properly handle a failed transaction.</p>
  
  <p>I am currenly handling it like so, but it feels more like a hack than a solution</p>
  
  <pre><code>def save(self, *args, **kwargs):
      while not self.id:
          try:
              self.position = self.parent.item_count
              super(Item, self).save(*args, **kwargs)
          except IntegrityError:
              # chill out, then try again
              time.sleep(0.5)
  </code></pre>
  
  <p>Any suggestions?</p>
  
  <h2>Update:</h2>
  
  <p>Another problem with the above solution is that the <code>while</code> loop will never end if <code>IntegrityError</code> is caused by a <code>name</code> conflict (or any other unique field for that matter). </p>
  
  <p>For the record, here's what I have so far which seems to do what I need:</p>
  
  <pre><code>def save(self, *args, **kwargs):   
      # for object update, do the usual save     
      if self.id: 
          super(Step, self).save(*args, **kwargs)
          return
  
      # for object creation, assign a unique position
      while not self.id:
          try:
              self.position = self.parent.item_count
              super(Step, self).save(*args, **kwargs)
          except IntegrityError:
              try:
                  rival = self.parent.item_set.get(position=self.position)
              except ObjectDoesNotExist: # not a conflict on "position"
                  raise IntegrityError
              else:
                  sleep(random.uniform(0.5, 1)) # chill out, then try again
  </code></pre>