Django多数据库:写入多个数据库
在Django的多数据库功能中,写一个可以支持主从架构的路由器相对简单。不过,能不能写一个路由器,让它同时往多个数据库里写数据呢?我这里有个需求,就是有一堆项目,都在同一个域名下。为了让用户不用在每个网站上都注册或登录,我想把contrib.auth
和contrib.sessions
这两个表的数据同步一下。请问在Django的多数据库功能下,这样做可行吗?还是说我应该去研究一下数据库系统(我用的是MySQL)的复制功能?
4 个回答
首先,我觉得你需要的是一个单点登录(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)
我觉得你可以考虑实现一个单点登录(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):
....
希望这对你有帮助 :)
我现在正在研究Django的分片架构。
我看过Django的路由功能,但决定自己写一个。
关于你的问题,我有一些想法:
- 一个想法是使用一个数据库,然后通过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通常是这样工作的)。
- 另一个想法:
根据你提到的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