mirror of
https://github.com/django/django.git
synced 2025-07-05 02:09:13 +00:00
[multi-db] Added ConnectionInfoDescriptor and attached it as db attribute in Manager class.
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3361 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
541ac3b990
commit
d96e3c93a5
@ -1,11 +1,20 @@
|
|||||||
|
from django import core
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.db import backend, connection
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.db import connections, _default
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.db.models import signals, get_apps, get_models
|
from django.db.models import signals, get_apps, get_models
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
from django.db.models.fields import FieldDoesNotExist
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Only exists in Python 2.4+
|
||||||
|
from threading import local
|
||||||
|
except ImportError:
|
||||||
|
# Import copy of _thread_local.py from Python 2.4
|
||||||
|
from django.utils._threading_local import local
|
||||||
|
|
||||||
# Size of each "chunk" for get_iterator calls.
|
# Size of each "chunk" for get_iterator calls.
|
||||||
# Larger values are slightly faster at the expense of more storage space.
|
# Larger values are slightly faster at the expense of more storage space.
|
||||||
GET_ITERATOR_CHUNK_SIZE = 100
|
GET_ITERATOR_CHUNK_SIZE = 100
|
||||||
@ -25,9 +34,78 @@ def ensure_default_manager(sender):
|
|||||||
cls.add_to_class('objects', Manager())
|
cls.add_to_class('objects', Manager())
|
||||||
dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
|
dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
|
||||||
|
|
||||||
|
class ConnectionInfoDescriptor(object):
|
||||||
|
"""Descriptor used to access database connection information from a
|
||||||
|
manager or other connection holder. Keeps a thread-local cache of
|
||||||
|
connections per instance, and always returns the same connection for an
|
||||||
|
instance in particular thread during a particular request.
|
||||||
|
|
||||||
|
Any object that includes an attribute ``model`` that holds a model class
|
||||||
|
can use this descriptor to manage connections.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.cnx = local()
|
||||||
|
self.cnx.cache = {}
|
||||||
|
|
||||||
|
def __get__(self, instance, type=None):
|
||||||
|
if instance is None:
|
||||||
|
raise AttributeError, \
|
||||||
|
"ConnectionInfo is accessible only through an instance"
|
||||||
|
instance_connection = self.cnx.cache.get(instance, None)
|
||||||
|
if instance_connection is None:
|
||||||
|
instance_connection = self.get_connection(instance)
|
||||||
|
def reset():
|
||||||
|
self.reset(instance)
|
||||||
|
dispatcher.connect(reset, signal=core.signals.request_finished)
|
||||||
|
self.cnx.cache[instance] = instance_connection
|
||||||
|
return instance_connection
|
||||||
|
|
||||||
|
def __set__(self, instance, value):
|
||||||
|
self.cnx.cache[instance] = instance_connection
|
||||||
|
|
||||||
|
def __delete__(self, instance):
|
||||||
|
self.reset(instance)
|
||||||
|
|
||||||
|
def get_connection(self, instance):
|
||||||
|
from django.conf import settings
|
||||||
|
app = instance.model._meta.app_label
|
||||||
|
model = instance.model.__name__
|
||||||
|
app_model = "%s.%s" % (app, model)
|
||||||
|
|
||||||
|
# Quick exit if no OTHER_DATABASES defined
|
||||||
|
if (not hasattr(settings, 'OTHER_DATABASES')
|
||||||
|
or not settings.OTHER_DATABASES):
|
||||||
|
return connections[_default]
|
||||||
|
# Look in MODELS for the best match: app_label.Model. If that isn't
|
||||||
|
# found, take just app_label. If nothing is found, use the default
|
||||||
|
maybe = None
|
||||||
|
for name, db_def in settings.OTHER_DATABASES.items():
|
||||||
|
if not 'MODELS' in db_def:
|
||||||
|
continue
|
||||||
|
mods = db_def['MODELS']
|
||||||
|
# Can't get a better match than this
|
||||||
|
if app_model in mods:
|
||||||
|
return connections[name]
|
||||||
|
elif app in mods:
|
||||||
|
if maybe is not None:
|
||||||
|
raise ImproperlyConfigured, \
|
||||||
|
"App %s appears in more than one OTHER_DATABASES " \
|
||||||
|
"setting (%s and %s)" % (maybe, name)
|
||||||
|
maybe = name
|
||||||
|
if maybe:
|
||||||
|
return connections[name]
|
||||||
|
# No named connection for this model; use the default
|
||||||
|
return connections[_default]
|
||||||
|
|
||||||
|
def reset(self, instance):
|
||||||
|
self.cnx.cache[instance] = None
|
||||||
|
|
||||||
|
|
||||||
class Manager(object):
|
class Manager(object):
|
||||||
# Tracks each time a Manager instance is created. Used to retain order.
|
# Tracks each time a Manager instance is created. Used to retain order.
|
||||||
creation_counter = 0
|
creation_counter = 0
|
||||||
|
db = ConnectionInfoDescriptor()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Manager, self).__init__()
|
super(Manager, self).__init__()
|
||||||
@ -119,8 +197,7 @@ class Manager(object):
|
|||||||
such as foreign key constraints for tables that don't exist at
|
such as foreign key constraints for tables that don't exist at
|
||||||
install time.)
|
install time.)
|
||||||
"""
|
"""
|
||||||
creator = self.model._meta.connection_info.get_creation_module()
|
builder = self.db.get_creation_module().builder
|
||||||
builder = creator.builder
|
|
||||||
run, pending = builder.get_create_table(self.model)
|
run, pending = builder.get_create_table(self.model)
|
||||||
run += builder.get_create_indexes(self.model)
|
run += builder.get_create_indexes(self.model)
|
||||||
if initial_data:
|
if initial_data:
|
||||||
@ -158,9 +235,8 @@ class Manager(object):
|
|||||||
def get_table_list(self):
|
def get_table_list(self):
|
||||||
"""Get list of tables accessible via my model's connection.
|
"""Get list of tables accessible via my model's connection.
|
||||||
"""
|
"""
|
||||||
info = self.model._meta.connection_info
|
builder = self.db.get_creation_module().builder
|
||||||
builder = info.get_creation_module.builder()
|
return builder.get_table_list(self.db)
|
||||||
return builder.get_table_list(info)
|
|
||||||
|
|
||||||
class ManagerDescriptor(object):
|
class ManagerDescriptor(object):
|
||||||
# This class ensures managers aren't accessible via model instances.
|
# This class ensures managers aren't accessible via model instances.
|
||||||
@ -172,3 +248,4 @@ class ManagerDescriptor(object):
|
|||||||
if instance != None:
|
if instance != None:
|
||||||
raise AttributeError, "Manager isn't accessible via %s instances" % type.__name__
|
raise AttributeError, "Manager isn't accessible via %s instances" % type.__name__
|
||||||
return self.manager
|
return self.manager
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user