Django4.0 多數(shù)據(jù)庫(kù)-手動(dòng)選擇數(shù)據(jù)庫(kù)

2022-03-16 17:38 更新

Django也提供允許在代碼中完全控制數(shù)據(jù)庫(kù)的API。手動(dòng)指定數(shù)據(jù)庫(kù)分配將優(yōu)先于路由分配的數(shù)據(jù)庫(kù)。

手動(dòng)為查詢集選擇數(shù)據(jù)庫(kù)

你可以在查詢集鏈的任一點(diǎn)為查詢集選擇數(shù)據(jù)庫(kù)。調(diào)用查詢集上的 ?using()? 就可以獲取使用指定數(shù)據(jù)庫(kù)的其他查詢集。
?using()? 使用單一參數(shù):你打算進(jìn)行查詢的數(shù)據(jù)庫(kù)別名。比如:

>>> # This will run on the 'default' database.
>>> Author.objects.all()

>>> # So will this.
>>> Author.objects.using('default').all()

>>> # This will run on the 'other' database.
>>> Author.objects.using('other').all()

為保存選擇數(shù)據(jù)庫(kù)

使用 ?using ?關(guān)鍵字來(lái) ?Model.save()? 到指定的數(shù)據(jù)保存的數(shù)據(jù)庫(kù)。
比如,要保存對(duì)象到 ?legacy_users數(shù)據(jù)庫(kù),你應(yīng)該這樣寫:

>>> my_object.save(using='legacy_users')

如果你沒有指定 ?using?,?save()? 方法將保存到路由的默認(rèn)數(shù)據(jù)庫(kù)分配。

將對(duì)象從一個(gè)數(shù)據(jù)庫(kù)移動(dòng)到另一個(gè)

如果已經(jīng)保存實(shí)例到數(shù)據(jù)庫(kù),它可能使用 ?save(using=...)? 作為遷移實(shí)例到新數(shù)據(jù)庫(kù)的方法。然而,如果沒有使用適合的步驟,這可能會(huì)產(chǎn)生意想不到的結(jié)果。
考慮下面的例子:

>>> p = Person(name='Fred')
>>> p.save(using='first')  # (statement 1)
>>> p.save(using='second') # (statement 2)

在語(yǔ)句1,新的 ?Person ?對(duì)象保存在 ?first ?數(shù)據(jù)庫(kù)。這一次,?p ?沒有主鍵,因此 Django 發(fā)出了一個(gè)SQL ?INSERT ?語(yǔ)句。這會(huì)創(chuàng)建主鍵,并且 Django 分配那個(gè)主鍵到 ?p?。
在語(yǔ)句2中進(jìn)行保存時(shí),?p ?也有主鍵值,Django 將試圖在新的數(shù)據(jù)庫(kù)上使用主鍵。如果主鍵值未在 ?second ?數(shù)據(jù)庫(kù)中使用,那么將不會(huì)有任何問(wèn)題——對(duì)象將被拷貝到新數(shù)據(jù)庫(kù)。
然而,如果 ?p ?的主鍵已經(jīng)在 ?second ?數(shù)據(jù)庫(kù)上使用,那么當(dāng)保存 ?p ?的時(shí)候, ?second ?數(shù)據(jù)庫(kù)中存在的對(duì)象將被覆蓋。
可以通過(guò)兩種方式避免這種情況。首先,可以清理實(shí)例主鍵。如果對(duì)象沒有主鍵,那么 Django 將它作為新對(duì)象來(lái)處理,避免在 ?second ?數(shù)據(jù)庫(kù)上造成任何數(shù)據(jù)丟失:

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.pk = None # Clear the primary key.
>>> p.save(using='second') # Write a completely new object.

第二個(gè)辦法就是使用 ?force_insert ?選項(xiàng)來(lái) ?save()? ,確保 Django 執(zhí)行了 SQL ?INSERT ?:

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.save(using='second', force_insert=True)

這將確保 ?Fred ?在兩個(gè)數(shù)據(jù)庫(kù)上擁有同一個(gè)主鍵。當(dāng)試著在 ?second ?上保存時(shí),如果主鍵已經(jīng)保存,那么將會(huì)引發(fā)一個(gè)錯(cuò)誤。

選擇要?jiǎng)h除的數(shù)據(jù)庫(kù)

默認(rèn)情況下,用來(lái)刪除現(xiàn)有對(duì)象的調(diào)用將在用于首先檢索對(duì)象的同一數(shù)據(jù)庫(kù)上執(zhí)行:

>>> u = User.objects.using('legacy_users').get(username='fred')
>>> u.delete() # will delete from the `legacy_users` database

指定將要?jiǎng)h除模型的數(shù)據(jù)庫(kù),傳遞 ?using ?關(guān)鍵字參數(shù)到 ?Model.delete()? 方法。這個(gè)參數(shù)的工作方式與用關(guān)鍵字參數(shù) ?save()? 是一樣的。
例如,如果你正在從 ?legacy_users ?遷移用戶到 ?new_users ?數(shù)據(jù)庫(kù),你可以使用這些命令:

>>> user_obj.save(using='new_users')
>>> user_obj.delete(using='legacy_users')

使用多個(gè)數(shù)據(jù)庫(kù)管理器

在管理器上使用 ?db_manager()? 方法來(lái)讓管理員訪問(wèn)非默認(rèn)數(shù)據(jù)庫(kù)。
比如,假設(shè)有一個(gè)自定義管理器方法來(lái)觸發(fā)數(shù)據(jù)庫(kù)——?User.objects.create_user()?。因?yàn)??create_user()? 是一個(gè)管理器方法,不是 ?QuerySet ?方法,你不能操作 ?User.objects.using('new_users').create_user()? 。(?create_user()? 方法只適用 ?User.objects? ,即管理器,而不是來(lái)自管理器上的 ?QuerySet ?。)解決方案是使用 ?db_manager()? ,像這樣:

User.objects.db_manager('new_users').create_user(...)

?db_manager()? 返回綁定到指定數(shù)據(jù)庫(kù)的管理器副本。

將 get_queryset() 和多個(gè)數(shù)據(jù)庫(kù)使用

如果在管理器上覆蓋了 ?get_queryset()? ,請(qǐng)確保在父類上調(diào)用這個(gè)方法使用 ?super()? 或者在管理器(包含使用的數(shù)據(jù)庫(kù)的名字)上適當(dāng)處理 ?_db? 屬性。
比如,如果你想從 ?get_queryset? 方法返回自定義的 ?QuerySet ?類,你可以這樣做:

class MyManager(models.Manager):
    def get_queryset(self):
        qs = CustomQuerySet(self.model)
        if self._db is not None:
            qs = qs.using(self._db)
        return qs


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)