diff --git a/django/db/__init__.py b/django/db/__init__.py
index 8395468..e3fcbbd 100644
a
|
b
|
|
| 1 | from threading import local |
1 | 2 | from django.conf import settings |
2 | 3 | from django.core import signals |
3 | 4 | from django.core.exceptions import ImproperlyConfigured |
… |
… |
router = ConnectionRouter(settings.DATABASE_ROUTERS)
|
24 | 25 | # by the PostgreSQL backends. |
25 | 26 | # we load all these up for backwards compatibility, you should use |
26 | 27 | # connections['default'] instead. |
27 | | connection = connections[DEFAULT_DB_ALIAS] |
| 28 | class DefaultConnectionProxy(local): |
| 29 | """ |
| 30 | Thread-local proxy for the default connection. |
| 31 | """ |
| 32 | def __getattr__(self, item): |
| 33 | return getattr(connections[DEFAULT_DB_ALIAS], item) |
| 34 | def __setattr__(self, name, value): |
| 35 | return setattr(connections[DEFAULT_DB_ALIAS], name, value) |
| 36 | connection = DefaultConnectionProxy() |
28 | 37 | backend = load_backend(connection.settings_dict['ENGINE']) |
29 | 38 | |
30 | 39 | # Register an event that closes the database connection |
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index f2bde84..0f4fc31 100644
a
|
b
|
try:
|
2 | 2 | import thread |
3 | 3 | except ImportError: |
4 | 4 | import dummy_thread as thread |
5 | | from threading import local |
6 | 5 | from contextlib import contextmanager |
7 | 6 | |
8 | 7 | from django.conf import settings |
… |
… |
from django.utils.importlib import import_module
|
13 | 12 | from django.utils.timezone import is_aware |
14 | 13 | |
15 | 14 | |
16 | | class BaseDatabaseWrapper(local): |
| 15 | class BaseDatabaseWrapper(object): |
17 | 16 | """ |
18 | 17 | Represents a database connection. |
19 | 18 | """ |
diff --git a/django/db/utils.py b/django/db/utils.py
index f0c13e3..41ad6df 100644
a
|
b
|
|
1 | 1 | import os |
| 2 | from threading import local |
2 | 3 | |
3 | 4 | from django.conf import settings |
4 | 5 | from django.core.exceptions import ImproperlyConfigured |
… |
… |
class ConnectionDoesNotExist(Exception):
|
50 | 51 | class ConnectionHandler(object): |
51 | 52 | def __init__(self, databases): |
52 | 53 | self.databases = databases |
53 | | self._connections = {} |
| 54 | self._connections = local() |
54 | 55 | |
55 | 56 | def ensure_defaults(self, alias): |
56 | 57 | """ |
… |
… |
class ConnectionHandler(object):
|
73 | 74 | conn.setdefault(setting, None) |
74 | 75 | |
75 | 76 | def __getitem__(self, alias): |
76 | | if alias in self._connections: |
77 | | return self._connections[alias] |
| 77 | if hasattr(self._connections, alias): |
| 78 | return getattr(self._connections, alias) |
78 | 79 | |
79 | 80 | self.ensure_defaults(alias) |
80 | 81 | db = self.databases[alias] |
81 | 82 | backend = load_backend(db['ENGINE']) |
82 | 83 | conn = backend.DatabaseWrapper(db, alias) |
83 | | self._connections[alias] = conn |
| 84 | setattr(self._connections, alias, conn) |
84 | 85 | return conn |
85 | 86 | |
| 87 | def __setitem__(self, key, value): |
| 88 | setattr(self._connections, key, value) |
| 89 | |
86 | 90 | def __iter__(self): |
87 | 91 | return iter(self.databases) |
88 | 92 | |
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index 936f010..be83a9a 100644
a
|
b
|
|
3 | 3 | from __future__ import with_statement, absolute_import |
4 | 4 | |
5 | 5 | import datetime |
| 6 | import threading |
6 | 7 | |
7 | 8 | from django.conf import settings |
8 | 9 | from django.core.management.color import no_style |
… |
… |
class FkConstraintsTests(TransactionTestCase):
|
446 | 447 | connection.check_constraints() |
447 | 448 | finally: |
448 | 449 | transaction.rollback() |
| 450 | |
| 451 | class ThreadTests(TestCase): |
| 452 | |
| 453 | def test_default_connection_thread_local(self): |
| 454 | """ |
| 455 | Ensure that the default connection (i.e. django.db.connection) is |
| 456 | different for each thread. |
| 457 | Refs #17258. |
| 458 | """ |
| 459 | connections_set = set() |
| 460 | connection.cursor() |
| 461 | connections_set.add(connection.connection) |
| 462 | def runner(): |
| 463 | from django.db import connection |
| 464 | connection.cursor() |
| 465 | connections_set.add(connection.connection) |
| 466 | for x in xrange(2): |
| 467 | t = threading.Thread(target=runner) |
| 468 | t.start() |
| 469 | t.join() |
| 470 | self.assertEquals(len(connections_set), 3) |
| 471 | |
| 472 | def test_connections_thread_local(self): |
| 473 | """ |
| 474 | Ensure that the connections are different for each thread. |
| 475 | Refs #17258. |
| 476 | """ |
| 477 | connections_set = set() |
| 478 | for conn in connections.all(): |
| 479 | connections_set.add(conn) |
| 480 | def runner(): |
| 481 | from django.db import connections |
| 482 | for conn in connections.all(): |
| 483 | connections_set.add(conn) |
| 484 | for x in xrange(2): |
| 485 | t = threading.Thread(target=runner) |
| 486 | t.start() |
| 487 | t.join() |
| 488 | self.assertEquals(len(connections_set), 6) |
| 489 | No newline at end of file |