classDatabaseErrorWrapper(object):""" Context manager and decorator that re-throws backend-specific database exceptions using Django's common wrappers. """def__init__(self,wrapper):""" wrapper is a database wrapper. It must have a Database attribute defining PEP-249 exceptions. """self.wrapper=wrapperdef__enter__(self):passdef__exit__(self,exc_type,exc_value,traceback):ifexc_typeisNone:returnfordj_exc_typein(DataError,OperationalError,IntegrityError,InternalError,ProgrammingError,NotSupportedError,DatabaseError,InterfaceError,Error,):db_exc_type=getattr(self.wrapper.Database,dj_exc_type.__name__)ifissubclass(exc_type,db_exc_type):dj_exc_value=dj_exc_type(*exc_value.args)dj_exc_value.__cause__=exc_valueifnothasattr(exc_value,'__traceback__'):exc_value.__traceback__=traceback# Only set the 'errors_occurred' flag for errors that may make# the connection unusable.ifdj_exc_typenotin(DataError,IntegrityError):self.wrapper.errors_occurred=Truesix.reraise(dj_exc_type,dj_exc_value,traceback)def__call__(self,func):# Note that we are intentionally not using @wraps here for performance# reasons. Refs #21109.definner(*args,**kwargs):withself:returnfunc(*args,**kwargs)returninnerdefload_backend(backend_name):""" Return a database backend's "base" module given a fully qualified database backend name, or raise an error if it doesn't exist. """# This backend was renamed in Django 1.9.ifbackend_name=='django.db.backends.postgresql_psycopg2':backend_name='django.db.backends.postgresql'try:returnimport_module('%s.base'%backend_name)exceptImportErrorase_user:# The database backend wasn't found. Display a helpful error message# listing all possible (built-in) database backends.backend_dir=os.path.join(os.path.dirname(upath(__file__)),'backends')try:builtin_backends=[namefor_,name,ispkginpkgutil.iter_modules([npath(backend_dir)])ifispkgandnamenotin{'base','dummy','postgresql_psycopg2'}]exceptEnvironmentError:builtin_backends=[]ifbackend_namenotin['django.db.backends.%s'%bforbinbuiltin_backends]:backend_reprs=map(repr,sorted(builtin_backends))error_msg=("%r isn't an available database backend.\n""Try using 'django.db.backends.XXX', where XXX ""is one of:\n%s\nError was: %s"%(backend_name,", ".join(backend_reprs),e_user))raiseImproperlyConfigured(error_msg)else:# If there's some other error, this must be an error in DjangoraiseclassConnectionDoesNotExist(Exception):passclassConnectionHandler(object):def__init__(self,databases=None):""" databases is an optional dictionary of database definitions (structured like settings.DATABASES). """self._databases=databasesself._connections=local()@cached_propertydefdatabases(self):ifself._databasesisNone:self._databases=settings.DATABASESifself._databases=={}:self._databases={DEFAULT_DB_ALIAS:{'ENGINE':'django.db.backends.dummy',},}ifself._databases[DEFAULT_DB_ALIAS]=={}:self._databases[DEFAULT_DB_ALIAS]['ENGINE']='django.db.backends.dummy'ifDEFAULT_DB_ALIASnotinself._databases:raiseImproperlyConfigured("You must define a '%s' database"%DEFAULT_DB_ALIAS)returnself._databasesdefensure_defaults(self,alias):""" Puts the defaults into the settings dictionary for a given connection where no settings is provided. """try:conn=self.databases[alias]exceptKeyError:raiseConnectionDoesNotExist("The connection %s doesn't exist"%alias)conn.setdefault('ATOMIC_REQUESTS',False)conn.setdefault('AUTOCOMMIT',True)conn.setdefault('ENGINE','django.db.backends.dummy')ifconn['ENGINE']=='django.db.backends.'ornotconn['ENGINE']:conn['ENGINE']='django.db.backends.dummy'conn.setdefault('CONN_MAX_AGE',0)conn.setdefault('OPTIONS',{})conn.setdefault('TIME_ZONE',None)forsettingin['NAME','USER','PASSWORD','HOST','PORT']:conn.setdefault(setting,'')defprepare_test_settings(self,alias):""" Makes sure the test settings are available in the 'TEST' sub-dictionary. """try:conn=self.databases[alias]exceptKeyError:raiseConnectionDoesNotExist("The connection %s doesn't exist"%alias)test_settings=conn.setdefault('TEST',{})forkeyin['CHARSET','COLLATION','NAME','MIRROR']:test_settings.setdefault(key,None)def__getitem__(self,alias):ifhasattr(self._connections,alias):returngetattr(self._connections,alias)self.ensure_defaults(alias)self.prepare_test_settings(alias)db=self.databases[alias]backend=load_backend(db['ENGINE'])conn=backend.DatabaseWrapper(db,alias)setattr(self._connections,alias,conn)returnconndef__setitem__(self,key,value):setattr(self._connections,key,value)def__delitem__(self,key):delattr(self._connections,key)def__iter__(self):returniter(self.databases)defall(self):return[self[alias]foraliasinself]defclose_all(self):foraliasinself:try:connection=getattr(self._connections,alias)exceptAttributeError:continueconnection.close()classConnectionRouter(object):def__init__(self,routers=None):""" If routers is not specified, will default to settings.DATABASE_ROUTERS. """self._routers=routers@cached_propertydefrouters(self):ifself._routersisNone:self._routers=settings.DATABASE_ROUTERSrouters=[]forrinself._routers:ifisinstance(r,six.string_types):router=import_string(r)()else:router=rrouters.append(router)returnroutersdef_router_func(action):def_route_db(self,model,**hints):chosen_db=Noneforrouterinself.routers:try:method=getattr(router,action)exceptAttributeError:# If the router doesn't have a method, skip to the next one.passelse:chosen_db=method(model,**hints)ifchosen_db:returnchosen_dbinstance=hints.get('instance')ifinstanceisnotNoneandinstance._state.db:returninstance._state.dbreturnDEFAULT_DB_ALIASreturn_route_dbdb_for_read=_router_func('db_for_read')db_for_write=_router_func('db_for_write')defallow_relation(self,obj1,obj2,**hints):forrouterinself.routers:try:method=router.allow_relationexceptAttributeError:# If the router doesn't have a method, skip to the next one.passelse:allow=method(obj1,obj2,**hints)ifallowisnotNone:returnallowreturnobj1._state.db==obj2._state.dbdefallow_migrate(self,db,app_label,**hints):forrouterinself.routers:try:method=router.allow_migrateexceptAttributeError:# If the router doesn't have a method, skip to the next one.continueallow=method(db,app_label,**hints)ifallowisnotNone:returnallowreturnTruedefallow_migrate_model(self,db,model):returnself.allow_migrate(db,model._meta.app_label,model_name=model._meta.model_name,model=model,)defget_migratable_models(self,app_config,db,include_auto_created=False):""" Return app models allowed to be synchronized on provided db. """models=app_config.get_models(include_auto_created=include_auto_created)return[modelformodelinmodelsifself.allow_migrate_model(db,model)]