首页 > 解决方案 > django 单个应用程序多个数据库:在所有数据库中创建相同的表

问题描述

我正在使用单个应用程序(app_name)测试开发一个 django 项目,我想在其中拥有 2 个模型(例如:model_Amodel_B),它们的实例存储在单独的数据库中(例如:DB_A.sqlite3DB_B.sqlite3)。我还有第三个 DB ( DB_users.sqlite3) 用于存储与身份验证、会话等相关的任何内容。

我正在尝试根据 django 文档实现多个数据库,使用数据库路由等,但我注意到在迁移时,在这 3 个数据库中的每一个中,都为这两个模型创建了不相关的表。例如,DB_A将创建my_app_model_A以及my_app_model_B创建表。但事情my_app_model_B应该只存储在DB_B.

这可能是什么原因/如何确保仅在正确的数据库中创建相关表?

=== 编辑===

让我确实添加代码,因为这将更容易审查。为简单起见,我将缩小到sqlite DB中的单个Document模型,以及用于用户信息、会话等的单独 sqlite DB。Django 项目名称为,django 应用程序名称为。当我创建文档或用户时,实例位于正确数据库中的正确表中,但是我看到的问题是两个数据库具有相同的表集,恕我直言,这很奇怪。例如db 也有所有的表(虽然是空的),而 db 有表(虽然是空的)。docsauthdocs_revreviewerdocsauth*authreviewer_document

我的代码: docs_rev\docs_rev\settings.py

...

DATABASES = {
    
    'default':{},

    'auth': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'auth.sqlite3'),
    },

    'docs' : {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'docs.sqlite3'),
    },
}

DATABASE_ROUTERS = [
    'reviewer.router.authRouter',
    'reviewer.router.docsRouter', 
]

...

docs_rev\docs_rev\urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('reviewer/', include ('reviewer.urls')),
    path('', RedirectView.as_view(url='reviewer/', permanent=True)),
    path('accounts/', include('django.contrib.auth.urls')),
]

docs_rev\reviewer\urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('docs/', views.DocsListView.as_view(), name='docs'),
    path('doc/<uuid:pk>', views.DocDetailView.as_view(), name='document-detail'),
]

docs_rev\reviewer\models.py

...
class Document(models.Model):

...
    class Meta:
        app_label = 'reviewer'

    def __str__(self):
        return str(self.id)
    
    def get_absolute_url(self):
        return reverse('document-detail', args=[str(self.id)])

docs_rev\reviewer\router.py

class authRouter:
    route_app_labels = {'admin', 'auth', 'contenttypes', 'flatpages', 'redirects', 'sessions', 'sites'}

    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'auth'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'auth'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if (
            obj1._meta.app_label in self.route_app_labels or
            obj2._meta.app_label in self.route_app_labels
        ):
           return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label in self.route_app_labels:
            return True
        return None

class docsRouter(object): 

    route_app_labels = {'reviewer'}

    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'docs'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'docs'
        return None
    
    def allow_relation(self, obj1, obj2, **hints):
        if obj1._meta.app_label in self.route_app_labels or \
           obj2._meta.app_label in self.route_app_labels:       
            return True
        return None
    
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label in self.route_app_labels:
            return True
        return None

标签: pythondjangodjango-models

解决方案


数据库路由器的重要部分是route_app_labels 确保这些应用程序始终使用指定的数据库。

https://docs.djangoproject.com/en/3.1/topics/db/multi-db/

class AuthRouter:
    route_app_labels = {'auth', 'contenttypes'}
    ...rest of router code...

此外,请仔细检查DATABASE_ROUTERSsettings.py 中的内容是否正确。

DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']

推荐阅读