Django multidb:写入多个数据库

发布于 2024-09-29 22:13:38 字数 348 浏览 2 评论 0原文

With Django multidb, it's fairly easy to write a router that runs a master/slave infrastructure. But is it possible to write a router that writes to multiple databases? My use case is a collection of projects, all running on the same domain. To save users from registering/login in on every site, I'd like to synchronize the contrib.auth and contrib.sessions tables. Is that possible with Django multidb or should I look into replication features of the database system (MySQL in my case)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

卖梦商人 2024-10-06 22:13:38

我认为你会更好地实现 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):
      ....

希望这会有所帮助:)

i think you will be better implementing an SSO or OAuth service

but if you want like to synchronize your table users between two database and if you are using your own UserModel you can do something like this

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')

you can also putting with a decorator like this, like this you can also use it for synchronizing other tables:

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):
      ....

Hope this will help :)

乄_柒ぐ汐 2024-10-06 22:13:38

我现在正在研究 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)

保存 User 对象(至少在单数据库模型上)似乎通过 django.contrib 内部发生的各种魔法在幕后保存会话、身份验证等数据,因此您可能不必这样做并找出所有这些数据库表的名称和类型。

为了支持这项工作的可能性,我发誓我最近在某个地方读到(可能是在 Alex Gaynor 的一篇博客文章中),如果一个对象有外键,Django 将尝试使用该对象所在的同一个数据库(出于明显的原因,根据 Django 通常的操作方式)。

  1. 另一个想法:

从您引用的 Django multiDB 页面上的示例中我想知道类似以下内容是否可行:

他们的示例代码:

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

可能的修改:

def allowed_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”函数更有用。但你明白了。

毫无疑问,您必须添加其他类型的模型才能使这项工作正常进行(所有身份验证内容,内容广泛)。

祝你好运!希望这在某种程度上有帮助。

我对您的发现和评论感兴趣!

新山

I'm working on a Django sharding schema right now.

i looked at the Django router but decided to roll my own.

some thoughts on your issue:

  1. One idea is to use one database and then copy over the appropriate data via the use of Django signals on post-save.

something like--

import settings.databases as dbs_list

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

saving User objects (at least on a single-DB model) seems to save session, auth, etc. data under the hood via the various magic occurring inside django.contrib, so there's a chance you might not have to go in and figure out the names and types of all these database tables.

in support of the possibility of this working, I swear I read somewhere recently (probably on one of Alex Gaynor's blog posts) that if an object has a foreign key Django will attempt to use the same DB the object lives on (for obvious reasons in light of the way Django typically operates).

  1. another idea:

from the example on the Django multiDB page you referenced I wonder if something like the following would work:

their sample code:

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

a possible modification:

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 '''

looking at it again, this code would probably be more useful as the "db_for_write" function. but you get the idea.

there are no doubt other types of model you would have to add to make this work (all the auth stuff, which is extensive).

good luck! hope this is helpful in some way.

i'm interested in your findings and comments!

jb

陌上芳菲 2024-10-06 22:13:38

首先,我认为您需要更多的 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)

First, I think what you need is more an SSO framework, like in this post

I tried mouad's answer, but I couldn't get class decorator working ... And it seems to me this solution does not allow to have custom save() in models.

More appropriate to my need, I've defined a custom generic class and simply override the save() function.

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

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

And then:

class MyObject(MultiDbModel):
    [...]
    def save(self, *args, **kwargs):
        [custom save]
        super(MyObject, self).save(args, kwargs)
山有枢 2024-10-06 22:13:38

这是我的 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}")

Here is my multidb_model.py which seems to handle foreign keys as well. Will update it if there are bugs but once you inherit from this class as per Stepahne's answer, this will handle foreign key saves.

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}")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文