11# Django's Atomic
22
3- This doc will discuss the behaviours available through Django's ` atomic `
3+ This doc will discuss the behaviours available through [ Django's ` atomic ` ] [ atomic ]
44and the outcomes people are usually trying to achieve with it.
5- It goes on to outline some pitfalls that can result from using ` atomic `
5+ It goes on to outline some pitfalls that can result from using [ ` atomic ` ] [ atomic ]
66and how Subatomic avoids them.
77
8- Django's ` atomic ` ensures database changes are committed together-or-not-at-all.
8+ Django's [ ` atomic ` ] [ atomic ] ensures database changes are committed together-or-not-at-all.
99It creates a savepoint or a transaction depending on two factors:
1010
1111- The arguments passed to it (` durable= ` and ` savepoint= ` ).
1212- If a database transaction is already open.
1313
1414## Behaviours
1515
16- The * Behaviours* which ` atomic ` exhibits are:
16+ The * Behaviours* which [ ` atomic ` ] [ atomic ] exhibits are:
1717
1818| ` savepoint= ` | ` durable=False ` (default) | ` durable=True ` |
1919| --- | --- | --- |
@@ -22,7 +22,7 @@ The *Behaviours* which `atomic` exhibits are:
2222
2323## Outcomes
2424
25- When people use ` atomic ` ,
25+ When people use [ ` atomic ` ] [ atomic ] ,
2626they're generally trying to achieve one of three * Outcomes* :
2727
28281 . to create a * transaction*
@@ -39,9 +39,9 @@ they're generally trying to achieve one of three *Outcomes*:
3939
4040Ideally, we should be able to look at a line of code and say what it will do.
4141
42- Because ` atomic ` 's behaviour depends on whether a transaction is already open,
42+ Because [ ` atomic ` ] [ atomic ] 's behaviour depends on whether a transaction is already open,
4343one must know the full call stack
44- to know what any particular ` atomic ` will do.
44+ to know what any particular [ ` atomic ` ] [ atomic ] will do.
4545If it is called in multiple code paths,
4646developers must know that it will do different database operations
4747depending on who calls it.
@@ -57,7 +57,7 @@ but cannot know if it is part of a larger suite of changes
5757managed by higher-level code
5858which must also be committed together.
5959
60- When low-level code uses ` atomic `
60+ When low-level code uses [ ` atomic ` ] [ atomic ]
6161to indicate that its changes should be atomic (* Outcome* ** 3** ),
6262this can have one of two effects:
6363
@@ -81,11 +81,11 @@ rather than run the risk of creating a transaction with the wrong scope.
8181
8282### Savepoints by default
8383
84- ` atomic ` defaults to * Behaviour* ** A**
84+ [ ` atomic ` ] [ atomic ] defaults to * Behaviour* ** A**
8585which creates savepoints by default
8686when there is already an open transaction.
8787
88- It's common to decorate functions with ` atomic `
88+ It's common to decorate functions with [ ` atomic ` ] [ atomic ]
8989to indicate that code should be atomic (* Outcome* ** 3** ),
9090but neglect to pass ` savepoint=False ` .
9191This results in more database queries than necessary.
@@ -102,7 +102,7 @@ a safe place to continue from after a failure within a transaction.
102102Ideally then, the logic for catching the failure and continuing a transaction
103103should be adjacent to the logic which creates the savepoint.
104104
105- When we use ` atomic ` as a decorator,
105+ When we use [ ` atomic ` ] [ atomic ] as a decorator,
106106we separate the savepoint creation from the error handling logic.
107107The decorated function will not be within a ` try:...except...: ` .
108108
@@ -111,7 +111,7 @@ can make it difficult to know
111111where continuing after rolling back a savepoint is intended to be handled,
112112or even if it is handled at all.
113113This is compounded by the fact that
114- because ` atomic ` 's API is ambiguous,
114+ because [ ` atomic ` ] [ atomic ] 's API is ambiguous,
115115it can be hard to know the intended * Outcome* .
116116
117117To encourage putting rollback logic alongside savepoint creation,
@@ -120,16 +120,16 @@ Subatomic's `savepoint` cannot be used as a decorator.
120120### Tests without after-commit callbacks
121121
122122To avoid leaking state between tests,
123- Django's ` TestCase ` runs each test within a transaction
123+ Django's [ ` TestCase ` ] [ TestCase ] runs each test within a transaction
124124which gets rolled back at the end of the test.
125125As a result,
126- ` atomic ` blocks encountered during the test
126+ [ ` atomic ` ] [ atomic ] blocks encountered during the test
127127will not create transactions
128128so no after-commit callbacks will be run.
129129
130130Even if Django wanted to simulate after-commit callbacks in tests,
131131it has no way to know which * Outcome* was intended
132- when it encounters an ` atomic ` block.
132+ when it encounters an [ ` atomic ` ] [ atomic ] block.
133133It might be running a high-level test where a transaction is intended
134134and callbacks should be run,
135135or a low-level test where an open transaction is assumed
@@ -138,9 +138,13 @@ and callbacks should _not_ be run.
138138Without Subatomic,
139139developers must either manually run after-commit callbacks in tests,
140140which is prone to error and omission,
141- or run the test using ` TransactionTestCase ` ,
141+ or run the test using [ ` TransactionTestCase ` ] [ TransactionTestCase ] ,
142142which can be very slow.
143143
144144Subatomic's ` transaction() ` function
145145will run after-commit callbacks automatically in tests
146146so that code behaves the same in tests as it does in production.
147+
148+ [ atomic ] : https://docs.djangoproject.com/en/stable/topics/db/transactions/#django.db.transaction.atomic
149+ [ TestCase ] : https://docs.djangoproject.com/en/stable/topics/testing/tools/#django.test.TestCase
150+ [ TransactionTestCase ] : https://docs.djangoproject.com/en/stable/topics/testing/tools/#django.test.TransactionTestCase
0 commit comments