diff --git a/django/db/backends/util.py b/django/db/backends/util.py
index 32e0f4f..30f0a16 100644
a
|
b
|
class CursorWrapper(object):
|
30 | 30 | def __iter__(self): |
31 | 31 | return iter(self.cursor) |
32 | 32 | |
| 33 | def __enter__(self): |
| 34 | return self |
| 35 | |
| 36 | def __exit__(self, type, value, traceback): |
| 37 | # Ticket #17671 - Close instead of passing thru to avoid backend |
| 38 | # specific behavior. |
| 39 | self.cursor.close() |
33 | 40 | |
34 | 41 | class CursorDebugWrapper(CursorWrapper): |
35 | 42 | |
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index 33f5003..900f692 100644
a
|
b
|
Unicode parameters (``password``, ``salt`` or ``encoded``). If any of the
|
144 | 144 | hashing methods need byte strings, you can use the |
145 | 145 | :func:`~django.utils.encoding.smart_str` utility to encode the strings. |
146 | 146 | |
| 147 | Using database cursors as context managers |
| 148 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 149 | |
| 150 | Prior to Python 2.6, database cursors could be used as a context manager. The |
| 151 | specific backend's cursor defined the behavior of the context manager. The |
| 152 | behavior of magic method lookups was changed with Python 2.7 and cursors were |
| 153 | no longer usable as context managers. |
| 154 | |
| 155 | Django 1.5 allows a cursor to be used as a context manager that is a shortcut |
| 156 | for the following, instead of backend specific behavior. |
| 157 | |
| 158 | .. code-block:: python |
| 159 | |
| 160 | c = connection.cursor() |
| 161 | try: |
| 162 | c.execute(...) |
| 163 | finally: |
| 164 | c.close() |
| 165 | |
147 | 166 | Features deprecated in 1.5 |
148 | 167 | ========================== |
149 | 168 | |
diff --git a/docs/topics/db/sql.txt b/docs/topics/db/sql.txt
index 19daffd..577c58b 100644
a
|
b
|
Here is an example of the difference between the two::
|
262 | 262 | [{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}] |
263 | 263 | |
264 | 264 | |
| 265 | |
265 | 266 | .. _transactions-and-raw-sql: |
266 | 267 | |
267 | 268 | Transactions and raw SQL |
… |
… |
technique, the underlying database library will automatically add quotes and
|
290 | 291 | escaping to your parameter(s) as necessary. (Also note that Django expects the |
291 | 292 | ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is used by the SQLite |
292 | 293 | Python bindings. This is for the sake of consistency and sanity.) |
| 294 | |
| 295 | .. versionchanged:: 1.5 |
| 296 | |
| 297 | :pep:`249` does not state whether a cursor should be usable as a context |
| 298 | manager. Prior to Python 2.7, a cursor was usable as a context manager due |
| 299 | an unexpected behavior in magic method lookups (`Python ticket #9220`_). |
| 300 | Django 1.5 explicitly added support to allow using a cursor as context |
| 301 | manager. |
| 302 | |
| 303 | .. _`Python ticket #9220`: http://bugs.python.org/issue9220 |
| 304 | |
| 305 | Using a cursor as a context manager: |
| 306 | |
| 307 | .. code-block:: python |
| 308 | |
| 309 | with connection.cursor() as c: |
| 310 | c.execute(...) |
| 311 | |
| 312 | is equivalent to: |
| 313 | |
| 314 | .. code-block:: python |
| 315 | |
| 316 | c = connection.cursor() |
| 317 | try: |
| 318 | c.execute(...) |
| 319 | finally: |
| 320 | c.close() |
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index 109e1a5..2258388 100644
a
|
b
|
class BackendTestCase(TestCase):
|
416 | 416 | with self.assertRaises(DatabaseError): |
417 | 417 | cursor.execute(query) |
418 | 418 | |
| 419 | def test_cursor_contextmanager(self): |
| 420 | """ |
| 421 | Test that cursors can be used as a context manager |
| 422 | """ |
| 423 | with connection.cursor() as cursor: |
| 424 | from django.db.backends.util import CursorWrapper |
| 425 | self.assertTrue(isinstance(cursor, CursorWrapper)) |
| 426 | |
419 | 427 | # We don't make these tests conditional because that means we would need to |
420 | 428 | # check and differentiate between: |
421 | 429 | # * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do). |