title: Django: Transaction and select_for_update()
body: <p>In my Django application I have the following two models:</p>
  
  <pre><code>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']
  
  
  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)])
  </code></pre>
  
  <p>The method <code>get_number_of_registered_tickets()</code> do I need at several places in my application (e.g. template rendering). So I thought it makes sense to put it into the model also because it's related to it and I often heard it's good to have "fat models and lightweight views".</p>
  
  <p>My problem now:
  In order to prevent that two people want to register for the event <em>in parallel</em>, I have to use locking. Example: Let's say there's one ticket left to register for. Now, to people are on my website and click "Register" simultaneously. Under unforunate circumstances, it could happen that both requests are valid and now I have more registrations than capacity.</p>
  
  <p>I'm relatively new to Django, but reading through the docs, I thought that <a href="https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update" rel="noreferrer"><code>select_for_update()</code></a> should be the solution, am I right here (I use PostgreSQL, so that should be supported)?</p>
  
  <p>However, the docs also say that using <code>select_for_update()</code> is only valid within a transcation.</p>
  
  <blockquote>
    <p>Evaluating a queryset with <code>select_for_update()</code> in autocommit mode on
    backends which support <code>SELECT ... FOR UPDATE</code> is a
    <a href="https://docs.djangoproject.com/en/dev/ref/exceptions/#django.db.transaction.TransactionManagementError" rel="noreferrer"><code>TransactionManagementError</code></a> error because the rows are not locked in
    that case. If allowed, this would facilitate data corruption and could
    easily be caused by calling code that expects to be run in a
    transaction outside of one.</p>
  </blockquote>
  
  <p>My idea was now to change my model method <code>get_number_of_registered_tickets()</code> and add <strong>select_for_update()</strong>:</p>
  
  <pre><code>def get_number_of_registered_tickets():
          return EventRegistration.objects.select_for_update().filter(event__exact=self).aggregate(total=Coalesce(Sum('number_tickets'), 0))['total']
  </code></pre>
  
  <p><strong>Different questions now:</strong></p>
  
  <ol>
  <li>Is using <code>select_for_update()</code> the right solution to my problem?</li>
  <li>Does it mean that I cannot use the method <code>get_number_of_registered_tickets()</code> in different views/templates now, given that it seems to only work within a transaction? Do I have to violate DRY here and copy and paste the query with select_for_update() to another place in my code?</li>
  <li>I tested it locally and Django does not raise the <code>TransactionManagementError</code> while being in autocommit mode (not using any transactions). What could be the reason or do I misunderstand something?</li>
  </ol>