Index: docs/topics/db/models.txt
===================================================================
--- docs/topics/db/models.txt	(revision 9084)
+++ docs/topics/db/models.txt	(working copy)
@@ -725,38 +725,8 @@
 --------------------
 
 Another common pattern is writing custom SQL statements in model methods and
-module-level methods. The object :class:`django.db.connection
-<django.db.backends.DatabaseWrapper>` represents the current database
-connection. To use it, call :meth:`connection.cursor()
-<django.db.backends.DatabaseWrapper.cursor>` to get a cursor object. Then, call
-``cursor.execute(sql, [params])`` to execute the SQL and
-:meth:`cursor.fetchone() <django.db.backends.CursorWrapper.fetchone>` or
-:meth:`cursor.fetchall() <django.db.backends.CursorWrapper.fetchall>` to return
-the resulting rows. For example::
+module-level methods. See :ref:`raw SQL <topic-db-sql>`.
 
-    def my_custom_sql(self):
-        from django.db import connection
-        cursor = connection.cursor()
-        cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
-        row = cursor.fetchone()
-        return row
-
-:class:`connection <django.db.backends.DatabaseWrapper>` and :class:`cursor
-<django.db.backends.CursorWrapper>` mostly implement the standard Python
-DB-API -- see :pep:`249` -- with the addition of Django's :ref:`transaction
-handling <topics-db-transactions>`. If you're not familiar with the Python
-DB-API, note that the SQL statement in :meth:`cursor.execute()
-<django.db.backends.CursorWrapper.execute>` uses placeholders, ``"%s"``, rather
-than adding parameters directly within the SQL. If you use this technique, the
-underlying database library will automatically add quotes and escaping to your
-parameter(s) as necessary. (Also note that Django expects the ``"%s"``
-placeholder, *not* the ``"?"`` placeholder, which is used by the SQLite Python
-bindings. This is for the sake of consistency and sanity.)
-
-A final note: If all you want to do is a custom ``WHERE`` clause, you can use
-the :meth:`~QuerySet.extra` lookup method, which lets you add custom SQL to a
-query.
-
 .. _model-inheritance:
 
 Model inheritance
Index: docs/topics/db/sql.txt
===================================================================
--- docs/topics/db/sql.txt	(revision 9084)
+++ docs/topics/db/sql.txt	(working copy)
@@ -5,16 +5,20 @@
 
 Feel free to write custom SQL statements in custom model methods and
 module-level methods. The object ``django.db.connection`` represents the
-current database connection. To use it, call ``connection.cursor()`` to get a
+current database connection, and ``django.db.transaction`` represents the
+current database transaction. To use it, call ``connection.cursor()`` to get a
 cursor object. Then, call ``cursor.execute(sql, [params])`` to execute the SQL
 and ``cursor.fetchone()`` or ``cursor.fetchall()`` to return the resulting
-rows. Example::
+rows, followed by ``transaction.commit_unless_managed()`` to commit the
+change. Example::
 
     def my_custom_sql(self):
-        from django.db import connection
+        from django.db import connection, transaction
         cursor = connection.cursor()
         cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
         row = cursor.fetchone()
+        cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
+        transaction.commit_unless_managed()
         return row
 
 ``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
@@ -31,5 +35,37 @@
 use the ``where``, ``tables`` and ``params`` arguments to the standard lookup
 API. 
 
+Transaction handling
+--------------------
+
+Django :ref:`transaction handling <topic-db-transactions>` offers a choice
+of different behaviors, if you're using a database that supports
+transactions.
+
+Raw SQL users should note that all their commands are actually always run
+inside a transaction, even when using Django in auto-commit mode. As per the
+standard `Python DB-API`, all database connections come wrapped inside a
+transaction. In the default Django auto-commit mode, it simulates
+auto-commit by regularly committing this underlying transaction, e.g. in
+``model.save()``.
+
+As a result, raw SQL users should call
+``transaction.commit_unless_managed()`` after ``cursor.execute()``, just as
+``model.save()`` does internally.
+
+Raw SQL users with PostgreSQL should note that once a PostgreSQL raises an
+exception, all subsequent SQL in the same transaction fails with the error
+"current transaction is aborted, queries ignored until end of transaction
+block". As a result, raw SQL users with PostgreSQL should additionally wrap
+commands that may throw IntegrityError inside savepoints. Example::
+
+    try:
+        sid = transaction.savepoint()
+        cursor.execute(XXX)
+        transaction.savepoint_commit(sid)
+    except IntegrityError:
+        transaction.savepoint_rollback(sid)
+        raise
+
 .. _Python DB-API: http://www.python.org/peps/pep-0249.html
 
