一、說明:
在開發 Django 專案的時候,很多時候都是使用一個資料庫,即 settings 中只有 default 資料庫,但是有一些專案確實也需要使用多個資料庫,這樣的專案,在資料庫配置和使用的時候,就比較麻煩一點。
二、Django使用多個資料庫中settings中的DATABASES的設定
2.1 預設只是用一個資料庫時 DATABASES 的設定(以 SQLite 為例)
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'db.sqlite3', } }
2.2 Django 資料庫支援的 ENGINE 型別
-
'django.db.backends.postgresql'
'django.db.backends.mysql'
'django.db.backends.sqlite3'
'django.db.backends.oracle'
2.3 設定了多個資料庫後 settings 中的 DATABASES 的設定
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'db.sqlite3', }, 'db1': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mysql_test_db1', 'USER': 'root', 'PASSWORD': 'Se7eN521', 'HOST': '127.0.0.1', 'PORT': '3306' }, 'db2': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mysql_test_db2', 'USER': 'root', 'PASSWORD': 'Se7eN521', 'HOST': '127.0.0.1', 'PORT': '3306' } }
三、實現思路
- 多個應用對應多個資料庫和一個應用對應多個資料庫
- 情況一:專案有多個 應用app 且需要使用到多個資料庫
- 情況二:專案只有一個應用app, 且但需要使用到多個資料庫,
- 這兩種情況的實現思路其實都是一樣的,都是為每個資料庫建立一個應用,即這個應用只對接一個資料庫,如果這個應用不需要寫任何業務邏輯的程式碼,也需要建立一個空的應用,主要是用來做資料庫遷移的
- 核心思想就是:一個model類對應一個資料庫,透過資料庫路由和model定義時指定的all_label來實現。
四、案例實現
第一步:建立需要的 應用app,並且在 INSTALLED_APPS 中引用
其中db1_app這個應用主要是用來對接資料庫db1的
其中db2_app這個應用主要是用來對接資料庫db2的
其中test_app這個應用主要用來實現業務邏輯的
第二步:建立 應用app 和 資料庫之間的對映關係
在settings.py 資料夾中設定 DATABASE_APPS_MAPPING 的字典,裡面主要是配置 應用app 和資料庫的對應關係
DATABASE_APPS_MAPPING = { "db1_app": "db1", # db1_app 對應 db1 資料庫 "db2_app": "db2" # db2_app 對應 db2 資料庫 }
第三步:建立資料庫路由
在專案的主資料夾即 settings.py 的同目錄下建立一個 database_router.py 檔案,該檔案的作用就是給不同應用app 配置不同的資料庫。
# _*_ coding:utf-8 _*_ # @Time : 2023/4/20 5:37 下午 from django.conf import settings DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING print('DATABASE_MAPPING = {}'.format(DATABASE_MAPPING)) class DatabaseAppsRouter(object): # 設定 應用app 讀取時資料庫的設定 def db_for_read(self, model, **hints)if model._meta.app_label in DATABASE_MAPPING: return DATABASE_MAPPING[model._meta.app_label] return None def db_for_write(self, model, **hints): if model._meta.app_label in DATABASE_MAPPING: return DATABASE_MAPPING[model._meta.app_label] return None def allow_relation(self, obj1, obj2, **hints): 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_migrate(self, db, app_label, model_name=None, **hints): """ Make sure that apps only appear in the related database. 根據app_label的值只在相應的資料庫中建立一個表,如果刪除該def或 不指定過濾條件,則一個Model會在每個資料庫裡都建立一個表。 """ if db in DATABASE_MAPPING.values():return DATABASE_MAPPING.get(app_label) == db elif app_label in DATABASE_MAPPING: return False return None
第四步:在setting.py中配置 DATABASE_ROUTERS 指定自由路由檔案:
#test_django為專案名,database_router為路由檔名,DatabaseAppsRouter為路由中建立的類名 DATABASE_ROUTERS = ['django_db_demo.database_router.DatabaseAppsRouter']
第五步:建立model類
說明:model 可以根據需要解除安裝任何一個應用app的model.py檔案中,也可以分散寫在多個應用的model.py中,這個根據自己的需要即可,但是如何推薦一定要在model類的Meta中指定app_label。不然會全部將表建立到default資料庫中
from django.db import models class SqliteModel(models.Model): """帳號和使用者關聯""" sqlite_name = models.CharField(max_length=20) class Meta: # 當前這個 SqliteModel 定義的資料庫的表將會建立在test_app 對應的default 資料庫中 app_label = "test_app" # 當有多個資料庫連結的時候,要透過app_label 來區分這個model對應那個資料庫 class Db1Model(models.Model): """帳號和使用者關聯""" db1_name = models.CharField(max_length=20) class Meta: # 當前這個Db1Model 定義的資料庫的表將會建立在 db1_app 對應的 db1 資料庫中 app_label = "db1_app" # 當有多個資料庫連結的時候,要透過app_label 來區分這個model對應那個資料庫 class Db2Model(models.Model): """帳號和使用者關聯""" db2_name = models.CharField(max_length=20) class Meta: # 當前這個Db2Model 定義的資料庫的表將會建立在 db2_app 對應的 db1 資料庫中 app_label = "db2_app" # 當有多個資料庫連結的時候,要透過app_label 來區分這個model對應那個資料庫
第六步:資料遷移
python3 manage.py makemigrations python3 manage.py migrate --database=default # 當有多個資料庫,需要遷移多次 python3 manage.py migrate --database=db1 python3 manage.py migrate --database=db2
第七步:檢視遷移:
model對應的表,分別遷移到不同的資料庫成功,剩下的增刪改查的就正常引入model物件即可,這樣就實現了,不同的model物件,對應不用資料庫的表。
第五步:總結
- 建立多個資料庫連線設定
- 建立多個資料與應用app的對映關係
- 建立資料庫路由
- 建立model類的時候置指明app_label,即這個model是屬於那個app,從而覺得遷移到那個資料庫