web/lib/django/db/utils.py
changeset 38 77b6da96e6f1
parent 29 cc9b7e14412b
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     1 import inspect
       
     2 import os
       
     3 
       
     4 from django.conf import settings
       
     5 from django.core.exceptions import ImproperlyConfigured
       
     6 from django.utils.importlib import import_module
       
     7 
       
     8 DEFAULT_DB_ALIAS = 'default'
       
     9 
       
    10 # Define some exceptions that mirror the PEP249 interface.
       
    11 # We will rethrow any backend-specific errors using these
       
    12 # common wrappers
       
    13 class DatabaseError(Exception):
       
    14     pass
       
    15 
       
    16 class IntegrityError(DatabaseError):
       
    17     pass
       
    18 
       
    19 
       
    20 def load_backend(backend_name):
       
    21     try:
       
    22         module = import_module('.base', 'django.db.backends.%s' % backend_name)
       
    23         import warnings
       
    24         warnings.warn(
       
    25             "Short names for DATABASE_ENGINE are deprecated; prepend with 'django.db.backends.'",
       
    26             PendingDeprecationWarning
       
    27         )
       
    28         return module
       
    29     except ImportError, e:
       
    30         # Look for a fully qualified database backend name
       
    31         try:
       
    32             return import_module('.base', backend_name)
       
    33         except ImportError, e_user:
       
    34             # The database backend wasn't found. Display a helpful error message
       
    35             # listing all possible (built-in) database backends.
       
    36             backend_dir = os.path.join(os.path.dirname(__file__), 'backends')
       
    37             try:
       
    38                 available_backends = [f for f in os.listdir(backend_dir)
       
    39                         if os.path.isdir(os.path.join(backend_dir, f))
       
    40                         and not f.startswith('.')]
       
    41             except EnvironmentError:
       
    42                 available_backends = []
       
    43             available_backends.sort()
       
    44             if backend_name not in available_backends:
       
    45                 error_msg = ("%r isn't an available database backend. \n" +
       
    46                     "Try using django.db.backends.XXX, where XXX is one of:\n    %s\n" +
       
    47                     "Error was: %s") % \
       
    48                     (backend_name, ", ".join(map(repr, available_backends)), e_user)
       
    49                 raise ImproperlyConfigured(error_msg)
       
    50             else:
       
    51                 raise # If there's some other error, this must be an error in Django itself.
       
    52 
       
    53 
       
    54 class ConnectionDoesNotExist(Exception):
       
    55     pass
       
    56 
       
    57 
       
    58 class ConnectionHandler(object):
       
    59     def __init__(self, databases):
       
    60         self.databases = databases
       
    61         self._connections = {}
       
    62 
       
    63     def ensure_defaults(self, alias):
       
    64         """
       
    65         Puts the defaults into the settings dictionary for a given connection
       
    66         where no settings is provided.
       
    67         """
       
    68         try:
       
    69             conn = self.databases[alias]
       
    70         except KeyError:
       
    71             raise ConnectionDoesNotExist("The connection %s doesn't exist" % alias)
       
    72 
       
    73         conn.setdefault('ENGINE', 'django.db.backends.dummy')
       
    74         if conn['ENGINE'] == 'django.db.backends.' or not conn['ENGINE']:
       
    75             conn['ENGINE'] = 'django.db.backends.dummy'
       
    76         conn.setdefault('OPTIONS', {})
       
    77         conn.setdefault('TEST_CHARSET', None)
       
    78         conn.setdefault('TEST_COLLATION', None)
       
    79         conn.setdefault('TEST_NAME', None)
       
    80         conn.setdefault('TEST_MIRROR', None)
       
    81         conn.setdefault('TIME_ZONE', settings.TIME_ZONE)
       
    82         for setting in ('NAME', 'USER', 'PASSWORD', 'HOST', 'PORT'):
       
    83             conn.setdefault(setting, '')
       
    84 
       
    85     def __getitem__(self, alias):
       
    86         if alias in self._connections:
       
    87             return self._connections[alias]
       
    88 
       
    89         self.ensure_defaults(alias)
       
    90         db = self.databases[alias]
       
    91         backend = load_backend(db['ENGINE'])
       
    92         conn = backend.DatabaseWrapper(db, alias)
       
    93         self._connections[alias] = conn
       
    94         return conn
       
    95 
       
    96     def __iter__(self):
       
    97         return iter(self.databases)
       
    98 
       
    99     def all(self):
       
   100         return [self[alias] for alias in self]
       
   101 
       
   102 
       
   103 class ConnectionRouter(object):
       
   104     def __init__(self, routers):
       
   105         self.routers = []
       
   106         for r in routers:
       
   107             if isinstance(r, basestring):
       
   108                 try:
       
   109                     module_name, klass_name = r.rsplit('.', 1)
       
   110                     module = import_module(module_name)
       
   111                 except ImportError, e:
       
   112                     raise ImproperlyConfigured('Error importing database router %s: "%s"' % (klass_name, e))
       
   113                 try:
       
   114                     router = getattr(module, klass_name)()
       
   115                 except AttributeError:
       
   116                     raise ImproperlyConfigured('Module "%s" does not define a database router name "%s"' % (module, klass_name))
       
   117             else:
       
   118                 router = r
       
   119             self.routers.append(router)
       
   120 
       
   121     def _router_func(action):
       
   122         def _route_db(self, model, **hints):
       
   123             chosen_db = None
       
   124             for router in self.routers:
       
   125                 try:
       
   126                     chosen_db = getattr(router, action)(model, **hints)
       
   127                     if chosen_db:
       
   128                         return chosen_db
       
   129                 except AttributeError:
       
   130                     # If the router doesn't have a method, skip to the next one.
       
   131                     pass
       
   132             try:
       
   133                 return hints['instance']._state.db or DEFAULT_DB_ALIAS
       
   134             except KeyError:
       
   135                 return DEFAULT_DB_ALIAS
       
   136         return _route_db
       
   137 
       
   138     db_for_read = _router_func('db_for_read')
       
   139     db_for_write = _router_func('db_for_write')
       
   140 
       
   141     def allow_relation(self, obj1, obj2, **hints):
       
   142         for router in self.routers:
       
   143             try:
       
   144                 allow = router.allow_relation(obj1, obj2, **hints)
       
   145                 if allow is not None:
       
   146                     return allow
       
   147             except AttributeError:
       
   148                 # If the router doesn't have a method, skip to the next one.
       
   149                 pass
       
   150         return obj1._state.db == obj2._state.db
       
   151 
       
   152     def allow_syncdb(self, db, model):
       
   153         for router in self.routers:
       
   154             try:
       
   155                 allow = router.allow_syncdb(db, model)
       
   156                 if allow is not None:
       
   157                     return allow
       
   158             except AttributeError:
       
   159                 # If the router doesn't have a method, skip to the next one.
       
   160                 pass
       
   161         return True