Django多数据库:写入多个数据库

6 投票
4 回答
5683 浏览
提问于 2025-04-16 06:13

在Django的多数据库功能中,写一个可以支持主从架构的路由器相对简单。不过,能不能写一个路由器,让它同时往多个数据库里写数据呢?我这里有个需求,就是有一堆项目,都在同一个域名下。为了让用户不用在每个网站上都注册或登录,我想把contrib.authcontrib.sessions这两个表的数据同步一下。请问在Django的多数据库功能下,这样做可行吗?还是说我应该去研究一下数据库系统(我用的是MySQL)的复制功能?

4 个回答

1

首先,我觉得你需要的是一个单点登录(SSO)框架,就像这篇文章里提到的那样。

我试过mouad的回答,但我没能让类装饰器正常工作……而且我觉得这个解决方案不允许在模型中使用自定义的save()方法。

为了更好地满足我的需求,我定义了一个自定义的通用类,并简单地重写了save()函数。

class MultiDbModel(models.Model):
    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        for dbname in settings.DATABASES:
            super(MultiDbModel, self).save(using=dbname)

然后:

class MyObject(MultiDbModel):
    [...]
    def save(self, *args, **kwargs):
        [custom save]
        super(MyObject, self).save(args, kwargs)
8

我觉得你可以考虑实现一个单点登录(SSO)或者OAuth服务。

不过,如果你想在两个数据库之间同步用户表,并且你使用的是自己的用户模型,你可以这样做:

class MyUser(models.Model):
    name = models.CharField(max_length=100)
    user = models.ForeignKey(User, unique=True)


    def save(self, ...): # ALL the signature
        super(MyUser, self).save(using='database_1')
        super(MyUser, self).save(using='database_2')

你也可以用装饰器来实现这样的方法,这样你也可以用它来同步其他表:

def save_multi_db(model_class):

    def save_wrapper(save_func): 
        def new_save(self, *args, **kws):
            super(model_class, self).save(using='database_1')
            super(model_class, self).save(using='database_1')
        return new_save

    func = getattr(model_class, 'save')
    setattr(model_class, 'save', save_wrapper(func)) 

    return save_wrapper

# and use it like this:

@save_multi_db
class MyUser(models.Model):
      ....

希望这对你有帮助 :)

4

我现在正在研究Django的分片架构。

我看过Django的路由功能,但决定自己写一个。

关于你的问题,我有一些想法:

  1. 一个想法是使用一个数据库,然后通过Django的信号机制在保存后复制合适的数据。

大概是这样的--

import settings.databases as dbs_list

def post_save_function(UserModel):
     for db in dbs_list:
          UserModel.save(using=db,force_insert=True)

保存用户对象(至少在单数据库模型下)似乎会在后台自动保存会话、认证等数据,这些都是Django内部的一些“魔法”在起作用,所以你可能不需要去搞清楚所有这些数据库表的名字和类型。

为了支持这个想法,我最近在某个地方(可能是Alex Gaynor的博客)看到过,如果一个对象有外键,Django会尝试使用这个对象所在的同一个数据库(这也是因为Django通常是这样工作的)。

  1. 另一个想法:

根据你提到的Django多数据库页面上的示例,我在想下面这样的代码是否可行:

他们的示例代码:

def allow_syncdb(self, db, model):
        "Explicitly put all models on all databases."
        return True

一个可能的修改:

def allow_syncdb(self, db, model):

    if isinstance(model,User):
         return True

    elif isinstance(model,Session):
         return True

    else:
         ''' something appropriate --
             whatever your sharding schema is for other objects '''

再看一遍,这段代码可能更适合用作“db_for_write”函数。不过你明白我的意思。

毫无疑问,你还需要添加其他类型的模型才能让这个工作(所有的认证相关内容,非常复杂)。

祝你好运!希望这些对你有帮助。

我很想知道你的发现和评论!

jb

撰写回答