| 1 | My configuration is: |
| 2 | |
| 3 | |
| 4 | {{{ |
| 5 | python 3.7.1 |
| 6 | }}} |
| 7 | |
| 8 | |
| 9 | {{{ |
| 10 | Django==2.2.24 |
| 11 | django-axes==5.16.0 |
| 12 | django-bootstrap-modal-forms==1.3.1 |
| 13 | django-celery-results==1.0.4 |
| 14 | django-cors-headers==3.1.1 |
| 15 | django-database-view==0.3.0 |
| 16 | django-debug-toolbar==1.11 |
| 17 | django-dynamic-db-router==0.3.0 |
| 18 | django-ipware==3.0.7 |
| 19 | django-redis-cache==3.0.0 |
| 20 | django-redis-sessions==0.6.2 |
| 21 | django-ses==1.0.3 |
| 22 | django-storages==1.12.3 |
| 23 | django-taggit==0.24.0 |
| 24 | djangorestframework==3.12.4 |
| 25 | pytest-django==4.4.0 |
| 26 | }}} |
| 27 | |
| 28 | I using Django with multiple databases and default DB is not set for security reasons (I prefer to get error if Django will fallback to `default` connection, because it means that current tenant DB is not used for some reasons). so `default` connection is empty (`{}`). |
| 29 | |
| 30 | When I run `python manage.py migrate --database=some_db_name` |
| 31 | |
| 32 | I've get error: |
| 33 | |
| 34 | {{{ |
| 35 | Applying app_name.0154_migration_name...Traceback (most recent call last): |
| 36 | File "manage.py", line 41, in <module> |
| 37 | execute_from_command_line(sys.argv) |
| 38 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line |
| 39 | utility.execute() |
| 40 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute |
| 41 | self.fetch_command(subcommand).run_from_argv(self.argv) |
| 42 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv |
| 43 | self.execute(*args, **cmd_options) |
| 44 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute |
| 45 | output = self.handle(*args, **options) |
| 46 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/core/management/base.py", line 83, in wrapped |
| 47 | res = handle_func(*args, **kwargs) |
| 48 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/core/management/commands/migrate.py", line 234, in handle |
| 49 | fake_initial=fake_initial, |
| 50 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/migrations/executor.py", line 117, in migrate |
| 51 | state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial) |
| 52 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards |
| 53 | state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial) |
| 54 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/migrations/executor.py", line 245, in apply_migration |
| 55 | state = migration.apply(state, schema_editor) |
| 56 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/migrations/migration.py", line 124, in apply |
| 57 | operation.database_forwards(self.app_label, schema_editor, old_state, project_state) |
| 58 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/dbview/helpers.py", line 21, in database_forwards |
| 59 | self._create_standard_view(model, schema_editor) |
| 60 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/dbview/helpers.py", line 60, in _create_standard_view |
| 61 | qs = str(model.view()) |
| 62 | File "/user/code/app_name/app_name/models/file_name.py", line 136, in view |
| 63 | return str(qs.query) |
| 64 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/query.py", line 265, in __str__ |
| 65 | sql, params = self.sql_with_params() |
| 66 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/query.py", line 273, in sql_with_params |
| 67 | return self.get_compiler(DEFAULT_DB_ALIAS).as_sql() |
| 68 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 474, in as_sql |
| 69 | extra_select, order_by, group_by = self.pre_sql_setup() |
| 70 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 54, in pre_sql_setup |
| 71 | self.setup_query() |
| 72 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 45, in setup_query |
| 73 | self.select, self.klass_info, self.annotation_col_map = self.get_select() |
| 74 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 254, in get_select |
| 75 | sql, params = self.compile(col, select_format=True) |
| 76 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 405, in compile |
| 77 | sql, params = node.as_sql(self, self.connection) |
| 78 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/expressions.py", line 737, in as_sql |
| 79 | return "%s.%s" % (qn(self.alias), qn(self.target.column)), [] |
| 80 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 396, in quote_name_unless_alias |
| 81 | r = self.connection.ops.quote_name(name) |
| 82 | File "/user/.pyenv/versions/gl/lib/python3.7/site-packages/django/db/backends/dummy/base.py", line 20, in complain |
| 83 | raise ImproperlyConfigured("settings.DATABASES is improperly configured. " |
| 84 | django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details. |
| 85 | }}} |
| 86 | |
| 87 | You can see that problem is here: |
| 88 | |
| 89 | {{{ |
| 90 | return self.get_compiler(DEFAULT_DB_ALIAS).as_sql() |
| 91 | }}} |
| 92 | |
| 93 | `DEFAULT_DB_ALIAS` is `default` and it hardcoded. |
| 94 | |
| 95 | Also `DEFAULT_DB_ALIAS` is used couple of times inside `django/db/models/sql/query.py` (please search by `DEFAULT_DB_ALIAS` in file to see details) |
| 96 | |
| 97 | It should use CURRENT_DB as other parts of Django |
| 98 | Unfortunately I didn't check how migration determines current DB when `--database=...` is set so can't recommend exact solution, but I may see couple hints: |
| 99 | |
| 100 | 1. DB may be get from `--database=...` directly (But not sure if that is a correct solution). |
| 101 | 2. DB may be get from [`DatabaseRouter`](https://docs.djangoproject.com/en/2.2/topics/db/multi-db/#database-routers) as other parts of Django (It is looking like correct solution) |
| 102 | 3. Here should be `using` option to be able set connection DB directly (for example, all functions inside `django/db/transaction.py` has `using` argument to be able set connection name directly) |
| 103 | |
| 104 | Right now I using workaround and set `from django.conf import settings; settings.DATABASES['default'] = current_db_taken_from_cmd` if command is `migrate`. |
| 105 | Not all migrations fail. I don't know reason why it happens only with specific migrations, but I guess that it because this migration doing `CreateView` |
| 106 | |
| 107 | Migration file is looking like: |
| 108 | |
| 109 | {{{ |
| 110 | # Generated by Django 2.2.10 on 2021-10-06 04:17 |
| 111 | from dbview.helpers import CreateView |
| 112 | |
| 113 | import common.enums.some_enum |
| 114 | from django.db import migrations, models |
| 115 | import django.db.models.deletion |
| 116 | |
| 117 | |
| 118 | class Migration(migrations.Migration): |
| 119 | |
| 120 | dependencies = [ |
| 121 | ('app_name', '0153_previous_migration'), |
| 122 | ] |
| 123 | |
| 124 | operations = [ |
| 125 | migrations.CreateModel( |
| 126 | name='SomeName', |
| 127 | fields=[ |
| 128 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
| 129 | ('create_datetime', models.DateTimeField(auto_now_add=True, verbose_name='A')), |
| 130 | ('user', models.CharField(default='admin', max_length=32, verbose_name='B')), |
| 131 | ('update_datetime', models.DateTimeField(auto_now=True, verbose_name='C')), |
| 132 | ... |
| 133 | ], |
| 134 | options={ |
| 135 | 'db_table': 'table_name', |
| 136 | 'unique_together': {('other_table', 'table_name')}, |
| 137 | }, |
| 138 | ), |
| 139 | CreateView( |
| 140 | name='SomeNameView', |
| 141 | fields=[ |
| 142 | ('table_name_1', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, primary_key=True, serialize=False, to='orm_django.ApplyingInformation')), |
| 143 | ('table_name_2', models.IntegerField(verbose_name='A')), |
| 144 | ('table_name_3', models.IntegerField(verbose_name='B')), |
| 145 | ('table_name_3', models.IntegerField(verbose_name='C')), |
| 146 | ... |
| 147 | ], |
| 148 | options={ |
| 149 | 'db_table': 'table_view', |
| 150 | }, |
| 151 | ), |
| 152 | migrations.AddIndex( |
| 153 | model_name='modelname', |
| 154 | index=models.Index(fields=['field_A', 'field_B', ...], name='index_name'), |
| 155 | ), |
| 156 | ] |
| 157 | }}} |