首页 > 解决方案 > Django 中间件将请求/响应路由到数据库模式

问题描述

我目前正在使用 django 中间件来处理使用 URL 对不同 postgresql 模式的请求/响应。我想使用另一个数据库来存储具有相同架构的历史数据:例如 - default_db{customer1 schema} 到 history_db {customer1 schema}。

中间件.py

from tenant.utils import set_tenant_schema_for_request


class TenantMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        set_tenant_schema_for_request(request)
        response = self.get_response(request)
        return response

utils.py 文件

from django.db import connection
from tenant.models import Tenant

def hostname_from_request(request):
    # split on `:` to remove port
    return request.get_host().split(":")[0].lower()


def tenant_schema_from_request(request):
    hostname = hostname_from_request(request)
    tenants_map = get_tenants_map()
    return tenants_map.get(hostname)


def set_tenant_schema_for_request(request):
    schema = tenant_schema_from_request(request)
    print(schema)
    with connection.cursor() as cursor:
        cursor.execute(f"SET search_path to {schema}")


def get_tenants_map():
    connection.cursor().execute(f"SET search_path to public")
    sub_domains = Tenant.objects.order_by('id').values_list("sub_domain", flat=True)
    schema_names = Tenant.objects.order_by('id').values_list("schema_name", flat=True)
    tenants = dict(zip(sub_domains, schema_names))
    return tenants
    # return {"customer1.example.com": "customer1",
    #         "customer2.example.com": "customer2",
    #         "example.com": "public"}

路由器.py 文件

from django.db import models


class HistoryRouter:
    history_app = {'history'}

    def db_for_read(self, model, **hints):
        """
        Attempts to read auth and contenttypes models go to auth_db.
        """

        if model._meta.app_label in self.history_app:
            return 'history_db'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.history_app:
            return 'history_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth or contenttypes apps is
        involved.
        """
        if (
                obj1._meta.app_label in self.history_app or
                obj2._meta.app_label in self.history_app
        ):
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth and contenttypes apps only appear in the
        'auth_db' database.
        """

        if db == 'history_db' and app_label in self.history_app:
            print('history_db')
            return True
        elif db == 'default' and app_label not in self.history_app:
            print('default_db')
            return True
        return False

中间件适用于默认数据库,但不适用于“history_db”。

设置.py 文件

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'my_db',
        'USER': 'postgres',
        'PASSWORD': 'admin,
        'HOST': 'localhost',
        'PORT': '5432',
    },
    'history_db': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'history_db',
        'USER': 'postgres',
        'PASSWORD': 'admin',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}
DATABASE_ROUTERS = ["tenant.router.HistoryRouter"]

MIDDLEWARE = [

    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',  # cors headers middleware
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    "tenant.middlewares.TenantMiddleware",  # custom middleware for tenants
]

问题 ::我希望将发送到 history_db 的请求发送到相关架构。我的默认数据库有模式 ['customer1', 'customer2', 'default'] 和 history_db 有模式 ['customer1', 'customer2', 'default']

标签: djangodjango-rest-framework

解决方案


推荐阅读