Not nesting version of @atomic() in Django?
<p>From the <a href="https://docs.djangoproject.com/en/dev/topics/db/transactions/#django.db.transaction.atomic">docs of atomic()</a></p>

<blockquote>
  <p>atomic blocks can be nested</p>
</blockquote>

<p>This sound like a great feature, but in my use case I want the opposite: I want the transaction to be durable as soon as the block decorated with <code>@atomic()</code> gets left successfully.</p>

<p>Is there a way to ensure durability in django's transaction handling?</p>

<h1>Background</h1>

<p>Transaction are ACID. The "D" stands for durability. That's why I think transactions can't be nested without loosing feature "D".</p>

<p>Example: If the inner transaction is successful, but the outer transaction is not, then the outer and the inner transaction get rolled back. The result: The inner transaction was not durable.</p>

<p>I use PostgreSQL, but AFAIK this should not matter much.</p>

<p>I agree with knbk's answer that it is not possible: durability is only present at the level of a transaction, and atomic provides that. It does not provide it at the level of save points. Depending on the use case, there may be workarounds.</p>

<p>I'm guessing your use case is something like:</p>

<pre><code>@atomic  # possibly implicit if ATOMIC_REQUESTS is enabled
def my_view():
    run_some_code()  # It's fine if this gets rolled back.
    charge_a_credit_card()  # It's not OK if this gets rolled back.
    run_some_more_code()  # This shouldn't roll back the credit card.
</code></pre>

<p>I think you'd want something like:</p>

<pre><code>@transaction.non_atomic_requests
def my_view():
    with atomic():
        run_some_code()
    with atomic():
        charge_a_credit_card()
    with atomic():
        run_some_more_code()
</code></pre>

<p>If your use case is for credit cards specifically (as mine was when I had this issue a few years ago), my coworker discovered that <a href="https://support.stripe.com/questions/does-stripe-support-authorize-and-capture">credit card processors actually provide mechanisms for handling this</a>. A similar mechanism might work for your use case, depending on the problem structure:</p>

<pre><code>@atomic
def my_view():
    run_some_code()
    result = charge_a_credit_card(capture=False)
    if result.successful:
        transaction.on_commit(lambda: result.capture())
    run_some_more_code()
</code></pre>

<p>Another option would be to use a non-transactional persistence mechanism for recording what you're interested in, like a log database, or a redis queue of things to record.</p>

python django postgresql transactions acid