1 """ |
|
2 15. Transactions |
|
3 |
|
4 Django handles transactions in three different ways. The default is to commit |
|
5 each transaction upon a write, but you can decorate a function to get |
|
6 commit-on-success behavior. Alternatively, you can manage the transaction |
|
7 manually. |
|
8 """ |
|
9 |
|
10 from django.db import models |
|
11 |
|
12 class Reporter(models.Model): |
|
13 first_name = models.CharField(maxlength=30) |
|
14 last_name = models.CharField(maxlength=30) |
|
15 email = models.EmailField() |
|
16 |
|
17 def __str__(self): |
|
18 return "%s %s" % (self.first_name, self.last_name) |
|
19 |
|
20 __test__ = {'API_TESTS':""" |
|
21 >>> from django.db import connection, transaction |
|
22 """} |
|
23 |
|
24 from django.conf import settings |
|
25 |
|
26 building_docs = getattr(settings, 'BUILDING_DOCS', False) |
|
27 |
|
28 if building_docs or settings.DATABASE_ENGINE != 'mysql': |
|
29 __test__['API_TESTS'] += """ |
|
30 # the default behavior is to autocommit after each save() action |
|
31 >>> def create_a_reporter_then_fail(first, last): |
|
32 ... a = Reporter(first_name=first, last_name=last) |
|
33 ... a.save() |
|
34 ... raise Exception("I meant to do that") |
|
35 ... |
|
36 >>> create_a_reporter_then_fail("Alice", "Smith") |
|
37 Traceback (most recent call last): |
|
38 ... |
|
39 Exception: I meant to do that |
|
40 |
|
41 # The object created before the exception still exists |
|
42 >>> Reporter.objects.all() |
|
43 [<Reporter: Alice Smith>] |
|
44 |
|
45 # the autocommit decorator works exactly the same as the default behavior |
|
46 >>> autocomitted_create_then_fail = transaction.autocommit(create_a_reporter_then_fail) |
|
47 >>> autocomitted_create_then_fail("Ben", "Jones") |
|
48 Traceback (most recent call last): |
|
49 ... |
|
50 Exception: I meant to do that |
|
51 |
|
52 # Same behavior as before |
|
53 >>> Reporter.objects.all() |
|
54 [<Reporter: Alice Smith>, <Reporter: Ben Jones>] |
|
55 |
|
56 # With the commit_on_success decorator, the transaction is only comitted if the |
|
57 # function doesn't throw an exception |
|
58 >>> committed_on_success = transaction.commit_on_success(create_a_reporter_then_fail) |
|
59 >>> committed_on_success("Carol", "Doe") |
|
60 Traceback (most recent call last): |
|
61 ... |
|
62 Exception: I meant to do that |
|
63 |
|
64 # This time the object never got saved |
|
65 >>> Reporter.objects.all() |
|
66 [<Reporter: Alice Smith>, <Reporter: Ben Jones>] |
|
67 |
|
68 # If there aren't any exceptions, the data will get saved |
|
69 >>> def remove_a_reporter(): |
|
70 ... r = Reporter.objects.get(first_name="Alice") |
|
71 ... r.delete() |
|
72 ... |
|
73 >>> remove_comitted_on_success = transaction.commit_on_success(remove_a_reporter) |
|
74 >>> remove_comitted_on_success() |
|
75 >>> Reporter.objects.all() |
|
76 [<Reporter: Ben Jones>] |
|
77 |
|
78 # You can manually manage transactions if you really want to, but you |
|
79 # have to remember to commit/rollback |
|
80 >>> def manually_managed(): |
|
81 ... r = Reporter(first_name="Carol", last_name="Doe") |
|
82 ... r.save() |
|
83 ... transaction.commit() |
|
84 >>> manually_managed = transaction.commit_manually(manually_managed) |
|
85 >>> manually_managed() |
|
86 >>> Reporter.objects.all() |
|
87 [<Reporter: Ben Jones>, <Reporter: Carol Doe>] |
|
88 |
|
89 # If you forget, you'll get bad errors |
|
90 >>> def manually_managed_mistake(): |
|
91 ... r = Reporter(first_name="David", last_name="Davidson") |
|
92 ... r.save() |
|
93 ... # oops, I forgot to commit/rollback! |
|
94 >>> manually_managed_mistake = transaction.commit_manually(manually_managed_mistake) |
|
95 >>> manually_managed_mistake() |
|
96 Traceback (most recent call last): |
|
97 ... |
|
98 TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK |
|
99 """ |
|