使用Django multidb,编写一个运行主/从基础架构的路由器相当容易。但是否可能编写一个可以向多个数据库写入的路由器?我的用例是一组在同一域上运行的项目。为了使用户不必在每个站点上注册/登录,我想同步contrib.auth
和contrib.sessions
表。这在Django multidb中是否可能,或者应该查看数据库系统(在我的情况下是MySQL)的复制功能?
使用Django multidb,编写一个运行主/从基础架构的路由器相当容易。但是否可能编写一个可以向多个数据库写入的路由器?我的用例是一组在同一域上运行的项目。为了使用户不必在每个站点上注册/登录,我想同步contrib.auth
和contrib.sessions
表。这在Django multidb中是否可能,或者应该查看数据库系统(在我的情况下是MySQL)的复制功能?
我认为你最好实现单点登录(SSO)或OAuth服务。
但是,如果你想要在两个数据库之间同步用户表,并且正在使用自己的UserModel,你可以像这样做:
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路由器,但决定自己编写。
以下是一些关于你的问题的想法:
类似这样--
import settings.databases as dbs_list
def post_save_function(UserModel):
for db in dbs_list:
UserModel.save(using=db,force_insert=True)
def allow_syncdb(self, db, model):
"Explicitly put all models on all databases."
return True
一个可能的修改:
定义允许同步数据库函数(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
首先,我认为你需要的更多是一个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)
import logging
from django.db import models
DEFAULT_DB = 'default' # main postgres host
MIRROR_COPY_DB = 'pg_mirror' # a copy original db, i.e. if you want to move your data and keep it in sync
class MultiPgDbModel(models.Model):
class Meta:
abstract = True
def save(self, *args, **kwarg):
super(MultiPgDbModel, self).save(using=DEFAULT_DB)
try:
fields = [field for field in self._meta.fields if field.get_internal_type() == 'ForeignKey']
for field in fields:
getattr(self, field.name).save(using=MIRROR_COPY_DB)
super(MultiPgDbModel, self).save(using=MIRROR_COPY_DB)
except Exception as e:
logging.exception(f"MultiPgDbModel.save unexpected error when saving to pg_mirror, object id "
f"{self.pk} of model {self._meta.model}. {e}")
contrib.auth
和contrib.sessions
)。如果可能的话,我想避免干扰Django本身。 - Benjamin Wohlwend