thirdparty/google_appengine/lib/django/tests/modeltests/transactions/models.py
author Pawel Solyga <Pawel.Solyga@gmail.com>
Mon, 18 May 2009 19:37:38 +0200
changeset 2327 6c7d0fba105c
parent 109 620f9b141567
permissions -rwxr-xr-x
Replace usage of feedparser for sanitizing html with new HtmlSanitizer module. HtmlSanitizer prevents from XSS attacks (Fixes issue 606).

"""
15. Transactions

Django handles transactions in three different ways. The default is to commit
each transaction upon a write, but you can decorate a function to get
commit-on-success behavior. Alternatively, you can manage the transaction
manually.
"""

from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(maxlength=30)
    last_name = models.CharField(maxlength=30)
    email = models.EmailField()

    def __str__(self):
        return "%s %s" % (self.first_name, self.last_name)

__test__ = {'API_TESTS':"""
>>> from django.db import connection, transaction
"""}

from django.conf import settings

building_docs = getattr(settings, 'BUILDING_DOCS', False)

if building_docs or settings.DATABASE_ENGINE != 'mysql':
    __test__['API_TESTS'] += """
# the default behavior is to autocommit after each save() action
>>> def create_a_reporter_then_fail(first, last):
...     a = Reporter(first_name=first, last_name=last)
...     a.save()
...     raise Exception("I meant to do that")
...
>>> create_a_reporter_then_fail("Alice", "Smith")
Traceback (most recent call last):
    ...
Exception: I meant to do that

# The object created before the exception still exists
>>> Reporter.objects.all()
[<Reporter: Alice Smith>]

# the autocommit decorator works exactly the same as the default behavior
>>> autocomitted_create_then_fail = transaction.autocommit(create_a_reporter_then_fail)
>>> autocomitted_create_then_fail("Ben", "Jones")
Traceback (most recent call last):
    ...
Exception: I meant to do that

# Same behavior as before
>>> Reporter.objects.all()
[<Reporter: Alice Smith>, <Reporter: Ben Jones>]

# With the commit_on_success decorator, the transaction is only comitted if the
# function doesn't throw an exception
>>> committed_on_success = transaction.commit_on_success(create_a_reporter_then_fail)
>>> committed_on_success("Carol", "Doe")
Traceback (most recent call last):
    ...
Exception: I meant to do that

# This time the object never got saved
>>> Reporter.objects.all()
[<Reporter: Alice Smith>, <Reporter: Ben Jones>]

# If there aren't any exceptions, the data will get saved
>>> def remove_a_reporter():
...     r = Reporter.objects.get(first_name="Alice")
...     r.delete()
...
>>> remove_comitted_on_success = transaction.commit_on_success(remove_a_reporter)
>>> remove_comitted_on_success()
>>> Reporter.objects.all()
[<Reporter: Ben Jones>]

# You can manually manage transactions if you really want to, but you
# have to remember to commit/rollback
>>> def manually_managed():
...     r = Reporter(first_name="Carol", last_name="Doe")
...     r.save()
...     transaction.commit()
>>> manually_managed = transaction.commit_manually(manually_managed)
>>> manually_managed()
>>> Reporter.objects.all()
[<Reporter: Ben Jones>, <Reporter: Carol Doe>]

# If you forget, you'll get bad errors
>>> def manually_managed_mistake():
...     r = Reporter(first_name="David", last_name="Davidson")
...     r.save()
...     # oops, I forgot to commit/rollback!
>>> manually_managed_mistake = transaction.commit_manually(manually_managed_mistake)
>>> manually_managed_mistake()
Traceback (most recent call last):
    ...
TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
"""