【问题标题】:dynamically set database based on request in django在 django 中根据请求动态设置数据库
【发布时间】:2015-02-08 16:38:01
【问题描述】:

我正在用 python-django 编写一个多租户应用程序。

我想根据每个请求设置数据库连接。我想我可以编写一个中间件,在其中设置要用于该特定数据库的数据库。

import re
from django.db import connections

class SetTenantDatabase(object):
    def process_request(self, request):
        pattern = re.compile("\\b(http://|https://|www.|.com|8000|:|//)\\W\\d+", re.I)
        words = request.get_host()        
        db_name = [pattern.sub("", words)][0].split('.')[0]
        connections.databases['new-alias'] = { 
        'default': {
                    'ENGINE': 'django.db.backends.postgresql_psycopg2',
                    'NAME': 'store1',
                    'USER': 'xxx',
                    'PASSWORD': 'xxx',
                    'HOST': '127.0.0.1',
    } 
                                              }
        conn = connections['new-alias']
        return None

但这不起作用。我应该怎么做。方法是否错误或解决方案是否可行,最后如何?

【问题讨论】:

    标签: python django multi-tenant django-database


    【解决方案1】:

    这就是答案,希望它对将来的人有所帮助:

    import re
    import threading 
    request_cfg = threading.local()
    
    
    class RouterMiddleware(object):
        def process_request( self, request):
            pattern = re.compile("\\b(http://|https://|www.|.com|8000|:|//)\\W\\d+", re.I)
            words = request.get_host()        
            db_name = [pattern.sub("", words)][0].split('.')[0]
            request_cfg.cfg = db_name
            return None
    
        def process_response( self, request, response ):
            if hasattr( request_cfg, 'cfg' ):
                del request_cfg.cfg
            return response
    
    
    class DatabaseRouter (object):
        def _default_db( self ):
            if hasattr( request_cfg, 'cfg' ):
                return request_cfg.cfg
            else:
                return 'default'
    
        def db_for_read( self, model, **hints ):
            return self._default_db()
    
        def db_for_write( self, model, **hints ):
            return self._default_db()
    

    谢谢

    【讨论】:

    • 如果可能的话,您能否在您的代码中添加一些解释。对像我这样的新手会有帮助
    • 你能解释一下 threading.Local 以及它将如何管理不同数据库的两个同时事务
    • 我将尝试为此提供一些解释。您可以在应用程序的某个文件中包含这些类,例如 middlewares.py。然后将路由器中间件添加到 settings.py 中的列表“MIDDLEWARE”,并将数据库路由器添加到名为“DATABASE_ROUTERS”的列表中。一旦你有了这些,中间件就会开始拦截请求数据包。
    • 这也是一个很好的资源,有类似的方法:dzone.com/articles/django-switching-databases
    【解决方案2】:

    也许你可以使用:

    https://docs.djangoproject.com/en/dev/topics/db/multi-db/#manually-selecting-a-database-for-a-queryset

    Entity.objects.using('context1').all()
    Entity.objects.using('context2').all()
    

    根据请求选择/使用数据库。您可以在配置中定义多个数据库:

    DATABASES = {
        'context1': {
            'NAME': 'context1',
            'ENGINE': 'db.engine.to.use',
            'USER': 'xxx',
            'PASSWORD': 'xxx'
        },
        'context2': {
            'NAME': 'context2',
            'ENGINE': 'db.engine.to.use',
            'USER': 'xxx',
            'PASSWORD': 'xxx'
        }
    }
    

    【讨论】:

    • 我正在创建数据库..所以它不会在数据库设置中
    猜你喜欢
    • 2022-01-17
    • 1970-01-01
    • 2021-05-03
    • 2018-12-18
    • 2014-09-10
    • 2021-08-10
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多