如何在Django 1.4中使用数据库路由器?

4

我一直在尝试设置Django 1.4.3使用多个数据库,但是我无论如何都不能使其正常工作。我阅读了文档和SO上的帖子,并执行了以下操作:

1)settings.py中添加第二个DB配置,如下所示:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/tmp/django.db',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    },
    'db1' : {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db1',
        'USER': 'fake',
        'PASSWORD': 'fake',
        'HOST': 'fake.host.com',
        'PORT': '3306',
    },
}

2) 创建一个 routers.py 文件,并定义一个数据库路由如下
(注意:根据 Stack Overflow 上的帖子,如果您在 models.py 中定义一个数据库路由,则该路由将无法工作)

class DBRouter(object):
    def db_for_read(self, model, **hints):
        return 'db1'

    def db_for_write(self, model, **hints):
        return 'db1'

    def allow_syncdb(self, db, model):
        return 'db1'

3) 将以下内容添加到 settings.py 文件中:
(注:根据 SO 帖子,这些行必须在 DATABASES 配置之后)

from django.db import connections
DATABASE_ROUTERS = ['fakeproject.routers.DBRouter',]

这是错误的。 不要在这里放置 from django.db import connections,因为它会导致路由器无法注册。

我的症状:
显然,我所有的调用都通过默认数据库路由。以下是详细信息:

  • 两个数据库设置都可以工作(我可以成功执行manage.py indpectdb --database db1)。

  • DATABASE_ROUTERS设置没有产生任何投诉(即使我将错误的路径放入DB路由器中,或者甚至放入非字符串对象)。

  • 当我尝试通过manage.py shell访问我的对象时,我可以使用MyModel.objects.all(),但是当我实际尝试迭代它时,我被告知no such table。默认数据库没有那个表,但是'db1'显然有它,因为我是通过在它上面使用inspectdb生成模型的。证明如下,如果我在db1default之间交换DB配置,我可以毫无问题地访问对象。

非常感谢任何帮助!

2个回答

3
我发现第三步中的语句 "from django.db import connections" 阻止了数据库路由器的注册。当我删除该语句后,路由器被注册并且一切都按预期工作了。

1

我认为问题可能是因为你的routers.py只返回对'db1'的引用,但是你说你只被路由到'default',我不确定(我希望它只被路由到'db1')。

routers.py中创建一个主路由器类,然后为每个数据库创建子类,并使用app_label字符串进行初始化,以便你可以将它们区分开来。

class MasterRouter(object):
    def __init__(self, app_label):
        super(MasterRouter, self).__init__()
        self.app_label = app_label

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

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

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

    def allow_syncdb(self, db, model):
        if db == 'default':
            return model._meta.app_label == self.app_label
        elif model._meta.app_label == self.app_label:
            return False
        return None

class DefaultRouter(MasterRouter):
    def __init__(self):
        super(DefaultRouter, self).__init__('default')

class DB1Router(MasterRouter):
    def __init__(self):
        super(DB1Router, self).__init__('db1')

然后在您的settings.py中声明路由器

DATABASE_ROUTERS = [ 'routers.DefaultRouter', 'routers.DB1Router' ]

当然,您可能希望以不同的方式设置您的MasterRouter类覆盖。


谢谢你的答案!但是,为什么添加一个子类可以解决这个问题呢? - Enno Shioji
DATABASE_ROUTERS 中,您需要两个类 - 每个数据库一个。我正在子类化,因为我喜欢DRY代码(您可以重写为两个类,但代码几乎相同)。 - danodonovan

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