使用 Django multidb,编写运行主/从基础设施的路由器相当容易。但是是否可以编写一个写入多个数据库的路由器?我的用例是一组项目,它们都在同一个域上运行。为了避免用户在每个站点上注册/登录,我想同步contrib.auth
和contrib.sessions
表。这对 Django multidb 是否可行,或者我应该研究数据库系统的复制功能(在我的例子中是 MySQL)?
4 回答
我认为您会更好地实施 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 路由器,但决定自己动手。
关于您的问题的一些想法:
- 一种想法是使用一个数据库,然后通过在保存后使用 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.contrib 中发生的各种魔法在后台保存会话、身份验证等数据,因此您可能不必进入并弄清楚所有这些数据库表的名称和类型。
为了支持这种工作的可能性,我发誓我最近在某个地方(可能在 Alex Gaynor 的一篇博客文章中)读到,如果一个对象有一个外键,Django 将尝试使用该对象所在的同一个数据库(出于显而易见的原因根据 Django 通常的操作方式)。
- 另一个想法:
从您引用的 Django multiDB 页面上的示例中,我想知道以下内容是否可行:
他们的示例代码:
def allow_syncdb(self, db, model):
"Explicitly put all models on all databases."
return True
可能的修改:
def allow_syncdb(自我,数据库,模型):
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”函数可能会更有用。但你明白了。
毫无疑问,您必须添加其他类型的模型才能使这项工作(所有 auth 的东西,这是广泛的)。
祝你好运!希望这在某种程度上有所帮助。
我对你的发现和评论很感兴趣!
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)
这是我的 multidb_model.py 似乎也可以处理外键。如果有错误,将对其进行更新,但是一旦根据 Stepahne 的回答从此类继承,这将处理外键保存。
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}")