Django多数据库路由

33

我一直在使用手动数据库选择来处理一个有两个分离数据库的项目。我已经在设置中定义了我的数据库。

阅读了一些资料之后,似乎数据库路由才是应该采用的方法。然而,在阅读文档和这里的一些相关帖子之后,我比以往更加困惑了。

在我的设置中,我有:

DATABASES = {
    'default': {
       .... 
    },
    'my_db2': {
       ....
    }
}

DATABASE_ROUTERS = ['myapp2.models.MyDB2Router',]

我知道我必须像下面这样定义我的路由器类(我认为在myapp2.models.py文件中):

I know I have to define my router class (I think in myapp2.models.py file) like so:

class MyDB2Router(object):
"""A router to control all database operations on models in
the myapp2 application"""

def db_for_read(self, model, **hints):
    if model._meta.app_label == 'myapp2':
        return 'my_db2'
    return None

def db_for_write(self, model, **hints):
    if model._meta.app_label == 'myapp2':
        return 'my_db2'
    return None

def allow_relation(self, obj1, obj2, **hints):
    if obj1._meta.app_label == 'myapp2' or obj2._meta.app_label == 'myapp2':
        return True
    return None

def allow_syncdb(self, db, model):

    if db == 'my_db2':
        return model._meta.app_label == 'myapp2'
    elif model._meta.app_label == 'myapp2':
        return False
    return None

那接下来呢?每个模型都需要一个 meta.app_label 吗?还是这是自动的? 除此之外,我仍然遇到了一个错误:

django.core.exceptions.ImproperlyConfigured: 导入数据库路由器 JournalRouter 出错:"不能导入名称为 connection 的模块"

有人能帮助我理解正在发生的事情以及出了什么问题吗?非常感谢任何帮助。


8
好的,我来翻译一下。我刚刚解决了自己的问题。路由器类放在/myapp2目录下的一个名为routers.py的单独文件中。不需要meta.app_label,我想它会自动分配。希望这能帮助到某个人。 - Darwin Tech
3
创建一个新的答案来回答你的问题,然后接受它。 - Ivan Kharlamov
只有在模型定义在models.py之外时,才需要使用app_label选项,否则它会自动分配。 - Alasdair
4个回答

31

好的,我刚解决了自己的问题。路由器类进入 /myapp2 下的一个名为 routers.py 的单独文件中。似乎不需要 meta.app_label,因为我猜它会自动分配。希望这能帮助一些人。我还在这里记录了该过程。


11
接受您的答案,这样其他人就更容易理解这是一个正确的答案。 - arulmr

6
没有帮助到我,所以我进行了一些调试。也许这些结果可以减轻别人的痛苦。 :) 在django 1.4中的问题是当django尝试导入自定义路由器类时发生的循环引用。 这发生在django.db.utils.ConnectionRouter中。在我的情况下,应用程序的__init__.py导入了一个模块(确切地说是tastypie.api),该模块又通过长链导入了django.db.models。这本身并不是坏事,但是models尝试从django.db导入connection,而那恰恰依赖于ConnectionRouter。这正是我们的旅程开始的地方。因此出现了错误。
这被描述为django < 1.6中的错误:https://code.djangoproject.com/ticket/20704,在django 1.6中有一个很好的小更改集: https://github.com/django/django/commit/6a6bb168be90594a18ab6d62c994889b7e745055 然而,我的解决方案是将routers.py从应用程序目录移动到项目目录。那里没有令人讨厌的依赖关系。

这是我解决问题的方法(以及@Janosch的提示) - hobs
我将我的路由类移动到了主项目中,这也为我解决了“无法导入名称connection”的错误。谢谢! - Steve Mayne

4

还有一个需要避免的错误是在路由器中导入模型,即使路由器在不同的文件中定义,这也会导致相同的错误。


1
谢谢 - 这节省了我很多时间! - Gill Bates
这非常重要!感谢您的回答。 - Thane Brimhall
即使是像 from app.models import some_fun 这样简单的代码,在 Django 1.5 中也会导致这个错误。 - hobs

3

如果你有一个应用程序使用多个数据库,你可以按应用程序和表的基础进行路由。例如,如果你的应用程序是“控制台”,你只想让“PoolServers”模型来自不同的后端,你可以将以下内容添加到routers.py中:

class PoolServerRouter(object): 
def db_for_read(self, model, **hints):
    "Point only reads to poolserver  model to 'hamburger'"
    if model._meta.app_label == 'console' and model._meta.db_table == 'PoolServers':
        return 'hamburger'
    return 'default'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接