在Django中使用多个数据库,只有一个表“Django_migrations”

2024-10-08 23:27:04 发布

您现在位置:Python中文网/ 问答频道 /正文

对于Django中的一个项目,我必须使用两个数据库:defaultremote。我已经创建了routers.py,一切正常。在

需要在远程数据库上创建一个表,我创建了migration,运行它,然后创建了表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

我是这样运行迁移的:

^{pr2}$

现在当我这么做的时候:

python manage.py runserver

我得到以下警告:

You have 1 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): my_app.
Run 'python manage.py migrate' to apply them.

my_app的表是在remote数据库中创建的,在remote数据库内的django_migrations中,迁移被标记为已应用。在

编辑:
如何强制Django只使用一个表django_migrations,但仍然将迁移应用到不同的数据库中?

如何在不同的数据库中应用迁移,以便不发出警告?在


Tags: djangopynone数据库appdbreturnremote
1条回答
网友
1楼 · 发布于 2024-10-08 23:27:04

多亏了对我问题的评论,我做了一些研究,得出了以下结论。在

使用多个数据库会导致在使用迁移时创建一个表django_migrations。正如来自Kamil Niski的注释所解释的那样,没有选项只在一个表django_migrations中记录迁移。这在读取文件^{}之后就清楚了。在

我将用一个项目foo和项目内的一个应用程序bar来举例说明。应用程序bar只有一个型号Baz。在

我们创建项目:

django-admin startproject foo

现在在主项目目录中有以下内容:

^{pr2}$

我习惯于将项目目录中的所有应用程序分组:

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_APPSfoo/settings.py)并创建迁移:

python manage.py makemigrations bar

在运行迁移之前,我们在bar应用程序中创建routers.py

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

将发出以下警告:

You have 1 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): bar.
Run 'python manage.py migrate' to apply them.

不过,一切似乎都很好。然而,有这个警告并不令人满意。在

正确的方法是按照这个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将标记迁移,使其应用于这两个数据库。另外,authadminsessions等的表将仅在default数据库中创建,如routers.py中所指定。remote数据库中的表django_migrations也将有这些迁移的记录。在

这是一个很长的阅读,但我希望它能对这一点有所启示,我认为官方没有对这个问题进行彻底的解释。在

相关问题 更多 >

    热门问题