新聞中心
使用多數(shù)據(jù)庫最簡(jiǎn)單的方式就是設(shè)置數(shù)據(jù)庫路由方案。默認(rèn)路由方案確保對(duì)象對(duì)原始數(shù)據(jù)庫保持粘性(比如,從 ?foo ?數(shù)據(jù)庫檢索到的對(duì)象將被保持到同一個(gè)數(shù)據(jù)庫)。默認(rèn)路由方案確保當(dāng)數(shù)據(jù)庫沒有指定時(shí),所有查詢回退到 ?default ?數(shù)據(jù)庫。

高邑網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)公司,高邑網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為高邑上1000+提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的高邑做網(wǎng)站的公司定做!
你無需執(zhí)行任何操作來激活默認(rèn)路由——在每個(gè) Django 項(xiàng)目上是開箱即用的。然而,如果想實(shí)現(xiàn)更多有趣的數(shù)據(jù)庫分配行為,可以定義和安裝自己的數(shù)據(jù)庫路由。
數(shù)據(jù)庫路由
數(shù)據(jù)庫路由是一個(gè)類,它提供四種方法:
db_for_read(model, **hints)
建議用于讀取?model?類型對(duì)象的數(shù)據(jù)庫。
如果數(shù)據(jù)庫操作可以提供有助于選擇數(shù)據(jù)庫的任何附加信息,它將在 ?hints ?中提供。
如果沒有建議,則返回 ?None ?。
db_for_write(model, **hints)
建議用于寫入?model?類型對(duì)象的數(shù)據(jù)庫。
如果數(shù)據(jù)庫操作可以提供有助于選擇數(shù)據(jù)庫的任何附加信息,它將在 ?hints ?中提供。
如果沒有建議,則返回 ?None ?。
allow_relation(obj1, obj2, **hints)
如果允許 ?obj1 ?和 ?obj2 ?之間的關(guān)系,返回 ?True ?。如果阻止關(guān)系,返回 ?False ?,或如果路由沒意見,則返回 ?None?。這純粹是一種驗(yàn)證操作,由外鍵和多對(duì)多操作決定是否應(yīng)該允許關(guān)系。
如果沒有路由有意見(比如所有路由返回 ?None?),則只允許同一個(gè)數(shù)據(jù)庫內(nèi)的關(guān)系。
allow_migrate(db, app_label, model_name=None, **hints)
決定是否允許遷移操作在別名為 ?db ?的數(shù)據(jù)庫上運(yùn)行。如果操作運(yùn)行,那么返回 ?True ?,如果沒有運(yùn)行則返回 ?False ?,或路由沒有意見則返回 ?None ?。
?app_label ?參數(shù)是要遷移的應(yīng)用程序的標(biāo)簽。
?model_name ?由大部分遷移操作設(shè)置來要遷移的模型的 ?model._meta.model_name? (模型 ?__name__? 的小寫版本) 的值。 對(duì)于 RunPython 和 RunSQL 操作的值是 ?None ?,除非它們提示要提供它。
?hints通過某些操作來向路由傳達(dá)附加信息。
當(dāng)設(shè)置 ?model_name ?,?hints? 通常包含 ?model?下的模型類。注意它可能是 ?historical model? ,因此沒有任何自定義屬性,方法或管理器。你應(yīng)該只能依賴 ?_meta? 。
這個(gè)方法也可以用于確定給定數(shù)據(jù)庫上模型的可用性。
?makemigrations ?會(huì)在模型變動(dòng)時(shí)創(chuàng)建遷移,但如果 ?allow_migrate()? 返回 ?False?,任何針對(duì) ?model_name? 的遷移操作會(huì)在運(yùn)行 ?migrate的時(shí)候跳過。對(duì)于已經(jīng)遷移過的模型,改變 ?allow_migrate()? 的行為,可能會(huì)破壞主鍵,格外表或丟失的表。當(dāng) ?makemigrations ?核實(shí)遷移歷史,它跳過不允許遷移的 app 的數(shù)據(jù)庫。
路由不是必須提供所有這些方法——它也許省略它們中的一個(gè)或多個(gè)。如果某個(gè)方法被省略,Django會(huì)在執(zhí)行相關(guān)檢查時(shí)候,跳過這個(gè)路由。
使用路由
數(shù)據(jù)庫路由 ?DATABASE_ROUTERS ?配置安裝。這個(gè)配置定義類名列表,每個(gè)類名指定了主路由?django.db.router?應(yīng)使用的路由。
Django 的數(shù)據(jù)庫操作使用主路由來分配數(shù)據(jù)庫使用。每當(dāng)查詢需要知道正在使用哪個(gè)數(shù)據(jù)庫時(shí),它會(huì)調(diào)用主路由,提供一個(gè)模型和提示(如果可用的話),然后 Django 會(huì)依次嘗試每個(gè)路由直到找到數(shù)據(jù)庫。如果沒有找到,它試著訪問提示實(shí)例的當(dāng)前 ?instance._state.db? 。如果沒有提供提示實(shí)例,或者 ?instance._state.db? 為 ?None ?,主路由將分配默認(rèn)數(shù)據(jù)庫。
例如我們有一些數(shù)據(jù)庫:一個(gè) ?auth ?應(yīng)用,和其他應(yīng)用使用帶有兩個(gè)只讀副本的主/副設(shè)置。以下是指定這些數(shù)據(jù)庫的設(shè)置:
DATABASES = {
'default': {},
'auth_db': {
'NAME': 'auth_db_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'swordfish',
},
'primary': {
'NAME': 'primary_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'spam',
},
'replica1': {
'NAME': 'replica1_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'eggs',
},
'replica2': {
'NAME': 'replica2_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'bacon',
},
}現(xiàn)在需要處理路由。首先需要一個(gè)將 ?auth ?和 ?contenttypes app? 的查詢發(fā)送到 ?auth_db ?的路由(?auth ?模型已經(jīng)關(guān)聯(lián)了 ?ContentType?,因此它們必須保存在同一個(gè)數(shù)據(jù)庫里):
class AuthRouter:
"""
A router to control all database operations on models in the
auth and contenttypes applications.
"""
route_app_labels = {'auth', 'contenttypes'}
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.route_app_labels:
return 'auth_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.route_app_labels:
return 'auth_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.route_app_labels or
obj2._meta.app_label in self.route_app_labels
):
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 app_label in self.route_app_labels:
return db == 'auth_db'
return None我們也需要一個(gè)發(fā)送所有其他應(yīng)用到主/副配置的路由,并且隨機(jī)選擇一個(gè)副本來讀?。?/p>
import random
class PrimaryReplicaRouter:
def db_for_read(self, model, **hints):
"""
Reads go to a randomly-chosen replica.
"""
return random.choice(['replica1', 'replica2'])
def db_for_write(self, model, **hints):
"""
Writes always go to primary.
"""
return 'primary'
def allow_relation(self, obj1, obj2, **hints):
"""
Relations between objects are allowed if both objects are
in the primary/replica pool.
"""
db_set = {'primary', 'replica1', 'replica2'}
if obj1._state.db in db_set and obj2._state.db in db_set:
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
All non-auth models end up in this pool.
"""
return True最后,在配置文件中,我們添加下面的代碼(用定義路由器的模塊的實(shí)際 Python 路徑替換 ?path.to.? ):
DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']處理路由的順序非常重要。路由將按照 ?DATABASE_ROUTERS ?里設(shè)置的順序查詢。在這個(gè)例子里, ?AuthRouter ?將在 ?PrimaryReplicaRouter ?前處理,因此,在做出其他決定之前,先處理與 ?auth ?相關(guān)的模型。如果 ?DATABASE_ROUTERS ?設(shè)置在其他順序里列出兩個(gè)路由,?PrimaryReplicaRouter.allow_migrate()? 將首先處理。?PrimaryReplicaRouter? 實(shí)現(xiàn)的特性意味著所有模型可用于所有數(shù)據(jù)庫。
安裝好這個(gè)設(shè)置,并按照 同步數(shù)據(jù)庫 的要求遷移所有的數(shù)據(jù)庫,讓我們運(yùn)行一些 Django 代碼:
>>> # This retrieval will be performed on the 'auth_db' database
>>> fred = User.objects.get(username='fred')
>>> fred.first_name = 'Frederick'
>>> # This save will also be directed to 'auth_db'
>>> fred.save()
>>> # These retrieval will be randomly allocated to a replica database
>>> dna = Person.objects.get(name='Douglas Adams')
>>> # A new object has no database allocation when created
>>> mh = Book(title='Mostly Harmless')
>>> # This assignment will consult the router, and set mh onto
>>> # the same database as the author object
>>> mh.author = dna
>>> # This save will force the 'mh' instance onto the primary database...
>>> mh.save()
>>> # ... but if we re-retrieve the object, it will come back on a replica
>>> mh = Book.objects.get(title='Mostly Harmless')這個(gè)例子定義了一個(gè)路由來處理與來自 ?auth ?應(yīng)用的模型交互,其他路由處理與所以其他應(yīng)用的交互。如果 ?default ?為空,并且不想定義一個(gè)全能數(shù)據(jù)庫來處理所有未指定的應(yīng)用,那么路由必須在遷移之前處理 ?INSTALLED_APPS ?的所有應(yīng)用名。
當(dāng)前標(biāo)題:創(chuàng)新互聯(lián)Django4.0教程:自動(dòng)數(shù)據(jù)庫路由
路徑分享:http://fisionsoft.com.cn/article/dhdjhco.html


咨詢
建站咨詢
