Django

时间:2017-11-06 12:06:29

标签: python django

例如假设我有100个使用WordPress的客户端,我必须在Django中编写一个服务,该服务应该从WordPress的MySQL DB中返回 posts 的列表。问题是100个客户端具有不同的数据库连接设置。

我知道我可以使用DatabaseRouter来切换已在设置中加载的数据库。但我不知道如何使单一模型类使用不同的数据库设置。

  • 我尝试过改变设置。
  • 我也试过改变模型的app_label

但我后来才明白,在Django中改变任何东西都意味着更少。

我的要求

我想创建一个模型并动态更改数据库连接。连接列表可以在managed数据库表中。但我不想不必要地加载所有连接设置或创建多个模型。

2 个答案:

答案 0 :(得分:2)

我做了类似的事情,但改变了mongodb连接。 我创建了一个GenericView,它选择连接并在get_queryset上使用它。

我使用django rest框架,所以我做了这样的事情:

class SwitchDBMixinView(object):
    model = None
    fields = None

    def initial(self, request, *args, **kwargs):
        result = super().initial(request, *args, **kwargs)
        if request.user.is_authenticated():
            request.user.database_connection.register()
        return result

    def get_object(self, *args, **kwargs):
        return super().get_object(*args, **kwargs).switch_db(self.get_db_alias())

    def get_db_alias(self):
        if self.request is None or not self.request.user.is_authenticated():
            return DEFAULT_CONNECTION_NAME
        return self.request.user.database_connection.name

    def get_queryset(self):
        return self.model.objects.using(self.get_db_alias()).all()

    def perform_destroy(self, instance):
        instance.switch_db(self.get_db_alias()).delete()

模特:

from mongoengine.connection import register_connection, get_connection
AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL')

class Connection(models.Model):
    class Meta:
        pass

    owner = models.OneToOneField(
        AUTH_USER_MODEL,
        related_name='database_connection',
    )

    uri = models.TextField(
        default=DefaultMongoURI()
    )

    def register(self):
        register_connection(
            self.name,
            host=self.uri,
            tz_aware=True,
        )
        get_connection(
            self.name,
            reconnect=True
        )

    def get_name(self):
        return 'client-%d' % self.owner.pk

    name = property(get_name)

    def __str__(self):
        return self.uri

答案 1 :(得分:1)

您可能需要查看django.db.connectionsdjango/db/__init__.py)和django.db.utils.ConnectionHandlerdjango.db.connections是其中的一个实例)。这应该允许您动态添加新的数据库配置而不进行黑客攻击settings.DATABASES(实际ConnectionHandler_databases构建它的settings.DATABASES属性。我无法确定,因为我从未尝试过,但它应该归结为

from django import db

def add_db(alias, connection_infos):
    databases = db.connections.databases
    if alias in databases:
        either_raise_or_log_and_ignore(your choice)
    db.connections.databases[alias] = connection_infos

其中connection_infos是一个类似于settings.DATABASES中预期的映射。

然后,主要是使用Queryset.using(alias)进行查询,即:

alias = get_alias_for_user(request.user)
posts = Post.objects.using(alias).all()

cf https://docs.djangoproject.com/en/1.11/topics/db/multi-db/#manually-selecting-a-database

这个恕我直言的主要问题(假设您设法制作出符合上述未经测试的建议的内容)是您必须将数据库用户/密码存储在某个地方,这可能是一个重大安全问题。我不知道你对数据库管理部分有多少控制权,但如果你能在所有这些数据库上添加一个具有相同密码(当然还有适当的权限)的'django'用户会更好,这样你就可以保留密码在您的设置文件中,而不是必须将其保留在主数据库中。