mik3y / django-db-multitenant

A simple multi-tenancy solution for Django apps.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

dbname not set at cursor create time

Neamat opened this issue · comments

I followed all the steps that you mentioned in your docs but I always get the same error "dbname not set at cursor create time" when I run the project. I even sent a static database name inside the mapper just to try it and it returned the same error. It looks like it cannot initiate with the default database that I already added inside the settings. Any suggestions?

Thank you for your reply.
The following is the error trace:

Unhandled exception in thread started by <function wrapper at 0x0000000003F77AC8>
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\django\utils\autoreload.py", line 226, in wrapper
    fn(*args, **kwargs)
  File "C:\Python27\lib\site-packages\django\core\management\commands\runserver.py", line 116, in inner_run
    self.check(display_num_errors=True)
  File "C:\Python27\lib\site-packages\django\core\management\base.py", line 426, in check
    include_deployment_checks=include_deployment_checks,
  File "C:\Python27\lib\site-packages\django\core\checks\registry.py", line 75, in run_checks
    new_errors = check(app_configs=app_configs)
  File "C:\Python27\lib\site-packages\django\core\checks\model_checks.py", line 28, in check_all_models
    errors.extend(model.check(**kwargs))
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 1170, in check
    errors.extend(cls._check_fields(**kwargs))
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 1247, in _check_fields
    errors.extend(field.check(**kwargs))
  File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 925, in check
    errors = super(AutoField, self).check(**kwargs)
  File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 208, in check
    errors.extend(self._check_backend_specific_checks(**kwargs))
  File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 317, in _check_backend_specific_checks
    return connections[db].validation.check_field(self, **kwargs)
  File "C:\Python27\lib\site-packages\django\db\backends\mysql\validation.py", line 18, in check_field
    field_type = field.db_type(connection)
  File "C:\Python27\lib\site-packages\django\db\models\fields\__init__.py", line 625, in db_type
    return connection.data_types[self.get_internal_type()] % data
  File "C:\Python27\lib\site-packages\django\db\__init__.py", line 36, in __getattr__
    return getattr(connections[DEFAULT_DB_ALIAS], item)
  File "C:\Python27\lib\site-packages\django\utils\functional.py", line 33, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Python27\lib\site-packages\django\db\backends\mysql\base.py", line 184, in data_types
    if self.features.supports_microsecond_precision:
  File "C:\Python27\lib\site-packages\django\utils\functional.py", line 33, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Python27\lib\site-packages\django\db\backends\mysql\features.py", line 53, in supports_microsecond_precision
    return self.connection.mysql_version >= (5, 6, 4) and Database.version_info >= (1, 2, 5)
  File "C:\Python27\lib\site-packages\django\utils\functional.py", line 33, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Python27\lib\site-packages\django\db\backends\mysql\base.py", line 359, in mysql_version
    with self.temporary_connection():
  File "C:\Python27\lib\contextlib.py", line 17, in __enter__
    return self.gen.next()
  File "C:\Python27\lib\site-packages\django\db\backends\base\base.py", line 564, in temporary_connection
    cursor = self.cursor()
  File "C:\Python27\lib\site-packages\django\db\backends\base\base.py", line 231, in cursor
    cursor = self.make_debug_cursor(self._cursor())
  File "C:\Python27\lib\site-packages\db_multitenant\db\backends\mysql\base.py", line 56, in _cursor
    cursor = super(DatabaseWrapper, self)._cursor()
  File "C:\Python27\lib\site-packages\django\db\backends\base\base.py", line 204, in _cursor
    self.ensure_connection()
  File "C:\Python27\lib\site-packages\django\db\backends\base\base.py", line 199, in ensure_connection
    self.connect()
  File "C:\Python27\lib\site-packages\django\db\backends\base\base.py", line 173, in connect
    self.init_connection_state()
  File "C:\Python27\lib\site-packages\django\db\backends\mysql\base.py", line 270, in init_connection_state
    with self.cursor() as cursor:
  File "C:\Python27\lib\site-packages\django\db\backends\base\base.py", line 231, in cursor
    cursor = self.make_debug_cursor(self._cursor())
  File "C:\Python27\lib\site-packages\db_multitenant\db\backends\mysql\base.py", line 65, in _cursor
    raise ImproperlyConfigured('dbname not set at cursor create time')
django.core.exceptions.ImproperlyConfigured: dbname not set at cursor create time

I guess it doesn't go to the middleware but I added the middleware as the first one in the middleware section. The following is the middleware section:


MIDDLEWARE_CLASSES = [
    'db_multitenant.middleware.MultiTenantMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

The following also is the database:

DATABASES = {
    
    'default': {
        #'ENGINE': 'django.db.backends.mysql',
        'ENGINE': 'db_multitenant.db.backends.mysql', 
        'NAME': 'tenant',
        'USER': 'tenantuser',
        'PASSWORD': 'tenantpwd',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

Please advise what would be the issue.. Thanks alot @stephane

How do you access your application (hostname)?

I have been tearing my hair out with this issue too... Adding print statements I can see that the DatabaseWrapper._cursor() method gets called several times at 'bootup', i.e. before any requests are sent, during which time the middleware is not even loaded (and so db_name is not set on thread_local, hence the exception).
Funnily enough DatabaseWrapper._cursor() doesn't seem to be called at all on requests, so I have just removed the exception raising and it seems to works fine (in debug on local, not tried on prod), which makes me wonder if there's any point it being there at all?

Edit: sorry, the above is incorrect. DatabaseWrapper._cursor() does get called in requests (that's what placing print statements when pulling an all-nighter will do to you!) but during 'bootup' it won't find the db_name on threadlocal because the middleware only kicks in and sets that when it receives requests.

The db queries which run at boot up prior to any requests are SET SQL_AUTO_IS_NULL = 0 and such. And it seems that these are only called on MYSQL and people have asked for them to be removed as they are aparently unecessary, and this may be the case on newer versions of django (see this post) which would explain why some people see this error, but others don't.

If my understanding is correct:

  • These queries will only go to the default database.
  • These queries are not actually required in the case of MYSQL, but other backends may require load time queries, in which case there is a problem with the overall approach we are using.

I'm wondering if we should raise the ImproperlyConfigured() exception in MultiTenantMiddleware.process_request() instead, which would resolve this issue. And replace the exception in DatabaseWrapper._cursor() with a printed warning because that will only happen if we haven't set in ENV, which infers we're using it from a manage.py command. But perhaps I'm missing something?

Using django 1.9.5

I've solve this issue setting the TENANT_DATABASE_NAME var to my main db. Nevertheless I'm not sure either why is not getting the correct database name.

I am also getting the same issue
raise ImproperlyConfigured('dbname not set at cursor create time').
Is there any solution.

I created a fork which I'm using as a workaround: https://github.com/andyhasit/django-db-multitenant

image
having same error on django 1.9

@andyhasit that means you want to fallback to the default DB when not set?

@stephane Yes, and that's what my fork does.

@andyhasit could you propose a PR against master, please?

I solve this problem adding:

'db_multitenant.middleware.MultiTenantMiddleware',

To the first MIDDLEWARE, as say the documentation:

MIDDLEWARE

Don't forget add in settings.py at the end file :

from db_multitenant.utils import update_from_env
update_from_env(database_settings=DATABASES['default'],
    cache_settings=CACHES['default'])