django多資料庫操作

星空28發表於2024-08-04

1. 讀寫分離

  • 192.168.1.2 default 主資料庫負責寫入
  • 192.168.1.3 slave 從資料庫負責讀取

2. 生成資料庫表

python manage.py makemigrations
分別遷移到主從資料庫
python manage.py migrate --database=default 
python manage.py migrate --database=slave 


多個app分表:分app運算元據庫  假設app01對應資料庫default,app02對應資料庫slave

python manage.py makemigrations
python manage.py migrate app01 --database=default 
python manage.py migrate app02 --database=slave

 

3. 開發時手動選擇使用資料庫

models.UserInfo.objects.using("default").create(title="admin")
models.UserInfo.objects.using("slave").all()

4. 多資料庫,多app操作配置

settings.py中增加資料庫配置

DATABASE_ROUTERS = ['KPIBackendSys.database_router.DatabaseAppsRouter']   # 讀寫檔案路徑

DATABASE_APPS_MAPPING = {
    'app01': 'default',
    'app02': 'slave',
}

DATABASES = {
    # 預設AI資料庫
    'default': {
        'ENGINE': 'mssql',                        # 要連線的 資料庫型別
        # 'ENGINE': 'sql_server.pyodbc',          # 要連線的 資料庫型別
        'NAME': db1,                # 要連線的 資料庫名
        'HOST': host,                      # 要連線的遠端資料庫的 ip地址
        'PORT': port,                           # 資料庫連線埠,mysql預設3306
        'USER': user,                         # 資料庫已有使用者名稱
        'PASSWORD': pwd,                   # 資料庫已有使用者密碼
        'OPTIONS': {
            'driver': 'ODBC Driver 17 for SQL Server',
            'MARS_Connection': True,
        },
    },
    'slave': {
        'ENGINE': 'mssql',
        # 'ENGINE': 'sql_server.pyodbc',          # 要連線的 資料庫型別
        'NAME': db2,
        'HOST': host,                  # 要連線的遠端資料庫的 ip地址
        'PORT': port,                       # 資料庫連線埠,mysql預設3306
        'USER': user,               # 資料庫已有使用者名稱
        'PASSWORD': pwd,                # 資料庫已有使用者密碼
        'OPTIONS': {
            'driver': 'ODBC Driver 17 for SQL Server',
            # 'MARS_Connection': True,
        },
    },
}

在settings.py同級目錄下增加database_router.py檔案

database_router.py

class DatabaseAppsRouter(object):
    def db_for_read(self, model, **hints):
        # 判斷模型類的元類中的app_label
        if model._meta.app_label in DATABASE_MAPPING:
            return DATABASE_MAPPING[model._meta.app_label]
        return None
        # 或直接判斷並返回資料庫
        if model._meta.app_label == 'app01':
            return default
        if model._meta.app_label == 'app02':
            return slave

    def db_for_write(self, model, **hints):
        """
        Point all write operations to the specific database.
        """
        if model._meta.app_label in DATABASE_MAPPING:
            return DATABASE_MAPPING[model._meta.app_label]
        return None
        # 或直接判斷並返回資料庫
        if model._meta.app_label == 'app01':
            return default
        if model._meta.app_label == 'app02':
            return slave

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow any relation between apps that use the same database.
        """
        db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
        db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
        if db_obj1 and db_obj2:
            if db_obj1 == db_obj2:
                return True
            else:
                return False
        return None

    def allow_syncdb(self, db, model):
        """
        Make sure that apps only appear in the related database.
        """
        if db in DATABASE_MAPPING.values():
            return DATABASE_MAPPING.get(model._meta.app_label) == db
        elif model._meta.app_label in DATABASE_MAPPING:
            return False
        return None

    def allow_migrate(self, db, app_label, model=None, **hints):
        """
        Make sure the auth app only appears in the 'auth_db' database.
        app_label, 表示使用的資料庫別名
        """
        if db in DATABASE_MAPPING.values():
            # 允許遷移到auth_db
            return DATABASE_MAPPING.get(app_label) == db
        elif app_label in DATABASE_MAPPING:
            return False
        # 不允許遷移
        return None

5. 同一個app下的模型儲存在不同的資料庫

使用database_router.py中的allow_migrate方法, 讀寫操作同樣需要指定資料庫

class DatabaseAppsRouter(object):
    def db_for_read(self, model, **hints):
        # 判斷模型類的元類中的app_label
        # 或直接判斷並返回資料庫
        if model._meta.model_name in [model1, model2]:
            return default
        if model._meta.model_name in [model3, model3]:
            return slave

    def db_for_write(self, model, **hints):
        # 或直接判斷並返回資料庫
        if model._meta.model_name in [model1, model2]:
            return default
        if model._meta.model_name in [model3, model3]:
            return slave

    def allow_migrate(self, db, app_label, model=None, **hints):
        
        if db == 'default':
          if model_name in ['model1', 'model2']:
            return True
          return False
         
        if db == 'slave':
          if model_name in ['model3', 'model4']:
            return True
          return False
        

相關文章