对于Django中的项目,我必须使用两个数据库:默认和远程。我创建了routers.py
,一切正常。
需要在远程数据库上创建一个表,然后我创建了迁移,然后运行它并创建了表django_migrations
。我只想在默认数据库中只有一个表django_migrations
。
routers.py
的相关部分在这里:
class MyRouter(object):
# ...
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'my_app':
return db == 'remote'
return None
我这样运行迁移:
python manage.py migrate my_app --database=remote
现在,当我这样做时:
python manage.py runserver
我收到以下警告:
您有1个未应用的迁移。在为应用程序迁移my_app之前,您的项目可能无法正常工作。
运行“ python manage.py migration”以应用它们。
my_app
的表是在remote
数据库中创建的,并且在django_migrations
数据库内的remote
中已将迁移标记为已应用。
编辑:
如何强制Django仅使用一个表 django_migrations
,但仍将迁移应用到不同的数据库中?
如何在不同的数据库中应用迁移,从而不发出警告?
答案 0 :(得分:2)
感谢对我的问题的评论,我进行了一些研究,并得出以下发现。
使用多个数据库会导致在使用迁移时创建表django_migrations
。正如Kamil Niski的注释所解释的,没有选项只能将迁移记录在一个表django_migrations
中。读取文件django/db/migrations/recorder.py
后,这一点很明显。
我将说明一个示例,该示例在项目内部有一个项目foo
和一个应用bar
。应用bar
仅具有一个模型Baz
。
我们创建项目:
django-admin startproject foo
现在我们在主项目目录中包含以下内容:
- foo
- manage.py
我习惯将所有应用分组到项目目录中:
mkdir foo/bar
python manage.py bar foo/bar
在文件foo/settings.py
中,我们将设置调整为使用两个不同的数据库,在本示例中,我们使用sqlite3
:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db1.sqlite3'),
},
'remote': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
}
}
现在我们运行迁移:
python manage.py migrate --database=default
这将运行所有迁移,--database=default
部分是可选的,因为如果未指定,Django将使用默认数据库。
Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying sessions.0001_initial... OK
Django已将所有迁移应用到默认数据库:
1 contenttypes 0001_initial 2019-11-13 16:51:04.767382 2 auth 0001_initial 2019-11-13 16:51:04.792245 3 admin 0001_initial 2019-11-13 16:51:04.827454 4 admin 0002_logentr 2019-11-13 16:51:04.846627 5 admin 0003_logentr 2019-11-13 16:51:04.864458 6 contenttypes 0002_remove_ 2019-11-13 16:51:04.892220 7 auth 0002_alter_p 2019-11-13 16:51:04.906449 8 auth 0003_alter_u 2019-11-13 16:51:04.923902 9 auth 0004_alter_u 2019-11-13 16:51:04.941707 10 auth 0005_alter_u 2019-11-13 16:51:04.958371 11 auth 0006_require 2019-11-13 16:51:04.965527 12 auth 0007_alter_v 2019-11-13 16:51:04.981532 13 auth 0008_alter_u 2019-11-13 16:51:05.004149 14 auth 0009_alter_u 2019-11-13 16:51:05.019705 15 auth 0010_alter_g 2019-11-13 16:51:05.037023 16 auth 0011_update_ 2019-11-13 16:51:05.054449 17 sessions 0001_initial 2019-11-13 16:51:05.063868
现在,我们创建模型Baz
:
models.py
:
from django.db import models
class Baz(models.Model):
name = models.CharField(max_length=255, unique=True)
将应用bar
注册到INSTALLED_APPS
(foo/settings.py
)中并创建迁移:
python manage.py makemigrations bar
在运行迁移之前,我们在routers.py
应用中创建bar
:
class BarRouter(object): def db_for_read(self, model, **hints): if model._meta.app_label == 'bar': return 'remote' return None def db_for_write(self, model, **hints): if model._meta.app_label == 'bar': return 'remote' return None def allow_relation(self, obj1, obj2, **hints): return None def allow_migrate(self, db, app_label, model_name=None, **hints): if app_label == 'bar': return db == 'remote' if db == 'remote': return False return None
并在foo/settings.py
中注册:
DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']
现在,简单的方法是将bar
的迁移运行到remote
数据库中:
python manage.py migrate bar --database=remote
Operations to perform: Apply all migrations: bar Running migrations: Applying bar.0001_initial... OK
迁移已应用于remote
数据库:
1 bar 0001_initial 2019-11-13 17:32:39.701784
当我们跑步时:
python manage.py runserver
将出现以下警告:
您有1个未应用的迁移。您的项目可能无法正常工作 直到您为应用应用迁移:bar。
运行“ python manage.py migration”以应用它们。
一切似乎都很好。但是,收到此警告并不令人满意。
正确的方法是按照此answer中的建议为每个数据库运行所有迁移。
它看起来像这样:
python manage.py migrate --database=default
python manage.py migrate --database=remote
,并为bar
创建了迁移之后:
python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote
路由器将注意仅在bar_baz
数据库中创建表remote
,但是Django将标记在两个数据库中应用的迁移。同样,auth
,admin
,sessions
等的表将仅在default
数据库中创建,如routers.py
中所指定。 django_migrations
数据库中的表remote
也将包含这些迁移的记录。
这是一本很长的书,但是我希望它能为我们提供一些启发,在我看来,documentation官方并未对此问题进行详尽的解释。