W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
使用多數(shù)據(jù)庫(kù)最簡(jiǎn)單的方式就是設(shè)置數(shù)據(jù)庫(kù)路由方案。默認(rèn)路由方案確保對(duì)象對(duì)原始數(shù)據(jù)庫(kù)保持粘性(比如,從 ?foo
?數(shù)據(jù)庫(kù)檢索到的對(duì)象將被保持到同一個(gè)數(shù)據(jù)庫(kù))。默認(rèn)路由方案確保當(dāng)數(shù)據(jù)庫(kù)沒有指定時(shí),所有查詢回退到 ?default
?數(shù)據(jù)庫(kù)。
你無需執(zhí)行任何操作來激活默認(rèn)路由——在每個(gè) Django 項(xiàng)目上是開箱即用的。然而,如果想實(shí)現(xiàn)更多有趣的數(shù)據(jù)庫(kù)分配行為,可以定義和安裝自己的數(shù)據(jù)庫(kù)路由。
數(shù)據(jù)庫(kù)路由是一個(gè)類,它提供四種方法:
建議用于讀取?model
?類型對(duì)象的數(shù)據(jù)庫(kù)。
如果數(shù)據(jù)庫(kù)操作可以提供有助于選擇數(shù)據(jù)庫(kù)的任何附加信息,它將在 ?hints
?中提供。
如果沒有建議,則返回 ?None
?。
建議用于寫入?model
?類型對(duì)象的數(shù)據(jù)庫(kù)。
如果數(shù)據(jù)庫(kù)操作可以提供有助于選擇數(shù)據(jù)庫(kù)的任何附加信息,它將在 ?hints
?中提供。
如果沒有建議,則返回 ?None
?。
如果允許 ?obj1
?和 ?obj2
?之間的關(guān)系,返回 ?True
?。如果阻止關(guān)系,返回 ?False
?,或如果路由沒意見,則返回 ?None
?。這純粹是一種驗(yàn)證操作,由外鍵和多對(duì)多操作決定是否應(yīng)該允許關(guān)系。
如果沒有路由有意見(比如所有路由返回 ?None
?),則只允許同一個(gè)數(shù)據(jù)庫(kù)內(nèi)的關(guān)系。
決定是否允許遷移操作在別名為 ?db
?的數(shù)據(jù)庫(kù)上運(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ù)庫(kù)上模型的可用性。
?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ù)庫(kù)。
路由不是必須提供所有這些方法——它也許省略它們中的一個(gè)或多個(gè)。如果某個(gè)方法被省略,Django會(huì)在執(zhí)行相關(guān)檢查時(shí)候,跳過這個(gè)路由。
數(shù)據(jù)庫(kù)路由 ?DATABASE_ROUTERS
?配置安裝。這個(gè)配置定義類名列表,每個(gè)類名指定了主路由?django.db.router
?應(yīng)使用的路由。
Django 的數(shù)據(jù)庫(kù)操作使用主路由來分配數(shù)據(jù)庫(kù)使用。每當(dāng)查詢需要知道正在使用哪個(gè)數(shù)據(jù)庫(kù)時(shí),它會(huì)調(diào)用主路由,提供一個(gè)模型和提示(如果可用的話),然后 Django 會(huì)依次嘗試每個(gè)路由直到找到數(shù)據(jù)庫(kù)。如果沒有找到,它試著訪問提示實(shí)例的當(dāng)前 ?instance._state.db
? 。如果沒有提供提示實(shí)例,或者 ?instance._state.db
? 為 ?None
?,主路由將分配默認(rèn)數(shù)據(jù)庫(kù)。
例如我們有一些數(shù)據(jù)庫(kù):一個(gè) ?auth
?應(yīng)用,和其他應(yīng)用使用帶有兩個(gè)只讀副本的主/副設(shè)置。以下是指定這些數(shù)據(jù)庫(kù)的設(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ù)庫(kù)里):
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ù)庫(kù)。
安裝好這個(gè)設(shè)置,并按照 同步數(shù)據(jù)庫(kù) 的要求遷移所有的數(shù)據(jù)庫(kù),讓我們運(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ù)庫(kù)來處理所有未指定的應(yīng)用,那么路由必須在遷移之前處理 ?INSTALLED_APPS
?的所有應(yīng)用名。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: