當前位置:
首頁 > 知識 > 如何切換到一個自定義Django用戶模型Mid-Project

如何切換到一個自定義Django用戶模型Mid-Project

如何切換到一個自定義Django用戶模型Mid-Project

打開今日頭條,查看更多圖片

Django文檔建議開發者始終使用一個自定義的用戶模型來啟動項目(即使它與Django的用戶模型一開始是相同的),以便在以後需要時更容易地進行自定義。但是,如果你在啟動一個項目時沒有看到這一點,或者繼承了一個沒有自定義用戶模型的項目,需要添加一個用戶模型,那麼你應該怎麼做呢?

在Caktus,當Django第一次添加對自定義用戶模型的支持時,我們仍然使用South進行遷移。難以置信!大約六年前,我寫了一篇關於遷移到自定義用戶模型的文章,當然,由於Django內置了對資料庫遷移的支持,這個模型在很大程度上已經過時了。因此,我覺得為那些需要在Django 2.0+上的現有項目添加自定義用戶模型的任何人編寫一篇新文章是有幫助的。

背景

在本文發布時,Django票數跟蹤器中針對這個問題添加進一步文檔的Ticket#25313是開放的。這個Ticket中包含了一些在切換到自定義用戶模型時需要遵循的高級步驟,我建議你首先熟悉這些步驟。正如文檔中「切換到一個自定義用戶模型mid-project」下面所指出的, 「在創建資料庫表之後更改AUTH_USER_MODEL要困難得多,比如,它會影響外部鍵和多對多關係。」

我放在下面的指南在一定程度上與Ticket #25313中的高級指南有一些不同,我認為(希望)它們是積極的和破壞性較小的方式。儘管如此,這個Ticket已經開放了四年多,這是有原因的,因為它很難。因此,正如這個Ticket中提到的:

在更改生產資料庫之前,請謹慎進行,並確保你有一個資料庫備份(以及一個恢復它的工作流程)。

概述

下面的步驟1和步驟2與2013年(大約是Django 1.5)的步驟1和步驟2相同,之後的情況會有所不同,因為我們現在使用的是Django的內置遷移(而不是South)。在高級層面上,我們的策略是在我們自己的應用程序中創建一個模型,它具有與auth.User相同的所有欄位,並使用相同的底層資料庫表。然後,我們為自定義用戶模型偽造初始遷移,並徹底測試更改,並將所有內容部署到生產環境中。一旦完成之後,你的項目中就會有一個自定義的用戶模型,正如Django文檔中建議的那樣,你可以繼續根據自己的喜好對它進行調整。

與其他一些方法(包括我2013年的文章)相反,這次我選擇更新現有的auth_user表,以幫助確保現有的外鍵引用保持完整。這樣做的缺點是,目前需要對資料庫進行一些手工操作。不過,如果你正在使用具有引用完整性檢查(你應該這樣做)的資料庫,那麼你在晚上就會睡得更安穩,因為你知道你沒有搞砸一個影響資料庫中所有用戶的數據遷移。

如果你(以及其他一些人)能夠確認以下內容對你有效,那麼這個過程的某些迭代可能會在某個時候被加入到Django文檔中。

遷移過程

下面是我切換到一個自定義用戶模型mid-project的方法:

0. 假設:

  • 你有一個沒有自定義用戶模型的現有項目。
  • 你正在使用Django的遷移,所有遷移都是最新的(並且已經應用到生產資料庫中)。
  • 你需要保留一組現有的用戶,以及指向Django內置User模型的任意數量的模型。

1、首先,評估任何第三方應用程序,確保它們沒有任何對Django的User模型的引用,或者即使引用了,也要使用Django的通用方法來引用用戶模型。

2、接下來,對你自己的項目執行相同的操作。遍歷代碼,尋找可能對User模型的任何引用,並用相同的泛型引用替換它們。簡而言之,你可以使用get_user_model()方法直接獲取模型,或者如果你需要為用戶模型創建一個外鍵或其他資料庫關係,則可以使用settings.AUTH_USER_MODEL (它只是一個與指向該用戶模型的appname.ModelName路徑相對應的簡單字元串。)

注意,get_user_model()不能在任何models .py文件中以模塊級別被調用(擴展為models.py導入的任何文件),因為你最終將得 到一個循環導入。通常,在可能的情況下,將get_user_model()的調用保存在一個方法中(因此它是在運行時被調用的,而不是 在載入被時調用的),並在所有其他情況中使用settings.AUTH_USER_MODEL,會變得更容易一些。這並不總是可行的(例如, 在創建ModelForm時),但是你在模塊級別上使用它的次數越少,就越可能避免循環導入。

3、啟動一個新的users應用程序(或者給它另一個你選擇的名字,比如accounts)。如果你喜歡,你可以使用一個現有的應用程序,但它必須是一個沒有任何預先存在的遷移歷史的應用程序,因為正如Django文檔中所提到的,「由於受到可交換模型的Django動態依賴特性的局限,由AUTH_USER_MODEL引用的模型必須在它的應用程序的第一次遷移中被創建 (通常稱為0001 _initial);不然的化,你就會遇到依賴問題。」

如何切換到一個自定義Django用戶模型Mid-Project

4、通過一個 db_table向users/models.py添加一個新的User模型,db_table將使該User模型使用與現有的 auth.User模型相同的資料庫表。為了在以後更新內容類型時變得簡單一點(並且如果你希望底層資料庫模式中的多對多表命名與你的用戶模型的名稱匹配的話),你應該像我在這裡所做的那樣稱它為User。如果你願意,稍後可以對它重命名。

如何切換到一個自定義Django用戶模型Mid-Project

5、為了方便起見,如果你希望在運行時通過admin來檢查這個用戶模型,請在users/admin.py中為此添加一個入口:

如何切換到一個自定義Django用戶模型Mid-Project

6、在 settings.py中,將 users 添加到 INSTALLED_APPS 中,並設置 AUTH_USER_MODEL = "users.User":

如何切換到一個自定義Django用戶模型Mid-Project

7、為你的新User模型創建一個初始遷移:

如何切換到一個自定義Django用戶模型Mid-Project

你應該會得到一個新的遷移文件users/migration /0001_initial.py。

8、因為auth_user表已經存在,所以在這種情況下,我們通常會使用python manage.py migrate users --fake-initial命令來偽造本次遷移。但是,如果你現在嘗試運行它,你將得到一個InconsistentMigrationHistory錯誤,因為Django會在偽造這個遷移之前進行一次完整性檢查,該檢查會阻止這個偽造遷移的應用。特別是,它不允許偽造此遷移,因為其他會依賴於它,也就是說,包含對settings.AUTH_USER_MODEL的引用的任何遷移都已經運行了。我並不完全確定Django為什麼對偽造遷移設置這種限制,因為所有的重點就是告訴它遷移實際上已經被應用了(如果你知道為什麼,請在下面評論)。相反,你也可以通過手動將你的新users應用程序的初始遷移添加到遷移歷史中來實現相同的結果:

如何切換到一個自定義Django用戶模型Mid-Project

如果你使用的是users以外的應用程序名稱,請使用包含你的用戶模型的Django應用程序的名稱替換上面一行中的users。

同時,讓我們用用戶模型的新app_label來更新django_content_types表,這樣對該內容類型的現有引用將保持不變。與之前的資料庫更改一樣,必須在運行migrate之前進行此更改。這樣做的原因是,migrate將創建任何不存在的內容類型,這將阻止你使用新的應用程序標籤去更新舊的內容類型(會返回一個「重複鍵值違反唯一約束」錯誤)。

如何切換到一個自定義Django用戶模型Mid-Project

同樣,如果你將應用程序命名為users以外的名稱,請確保使用你選擇的應用程序名稱更新上面的SET app_label = "users"。

注意,此SQL只用於Postgres,對於其他資料庫後端可能會有所不同。

9、此時,你應該停止並將所有內容部署到模擬環境中,因為在手動調整遷移歷史之前嘗試運行遷移將會失敗。如果你的自動化部署過程運行了migrate(它可能會這樣做),那你需要在migrate之前運行這兩個SQL語句去更新這個過程 (尤其是因為migrate會為你創建任何不存在的內容類型,從而防止你在沒有進一步調整的情況下更新資料庫中的現有內容類型)。在模擬環境中徹底測試這個過程(甚至可能會多次),以確保你正確地自動化了所有內容。

10、在測試和修復任何錯誤之後,並在確保你有良好的備份和在出現問題時恢復它的流程之後,你就應該將目前為止的所有內容部署到生產環境中(和/或你需要保存現有用戶資料庫的任何其他環境)。

11、現在,你應該能夠對你的users.User模型進行更改,並根據需要運行 makemigrations / migrate。例如,作為第一步,你可能希望將auth_user表重命名為你的users應用程序名稱空間中的某個名稱。你可以通過從你的User模型中刪除db_table來實現這一點,所以它看起來是這樣的:

如何切換到一個自定義Django用戶模型Mid-Project

你還需要創建和運行一個新的遷移,使這個更改在資料庫中生效:

如何切換到一個自定義Django用戶模型Mid-Project

成功了嗎?

應該是這樣。現在,你應該可以對你自定義的User模型進行其他更改了(並為這些更改創建遷移)。你可以進行哪種類型的更改以及如何進行這些更改超出了本文的範圍,所以我建議你仔細閱讀Django文檔中關於如何替換自定義User模型的內容。如果你選擇從AbstractUser切換到AbstractBaseUser,請確保在從資料庫中刪除這些列之前,為你想保留的AbstractUser提供的任何欄位創建數據遷移。想了解更多關於這個話題的信息,請查看我們關於2017年度Django大會的文章,其中我們鏈接到了Julia M Looney的一篇題為「充分利用Django的用戶模型」的演講。我的同事Dmitriy也有一個很棒的帖子,裡面有一些其他的建議,可以幫助你挑選舊的項目。

再次強調一下,在生產環境中進行測試之前,請在模擬環境中仔細測試,並確保你有一個工作資料庫備份。祝你好運,請在下面評論任何成功或失敗的故事,或者關於如何改進這個過程的想法!


英文原文:https://www.caktusgroup.com/blog/2019/04/26/how-switch-custom-django-user-model-mid-project/

譯者:一瞬

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python部落 的精彩文章:

Netflix:你看的每一部電影背後都有Python編程語言的影子
5千萬的 Twisted 下載量是不會錯的

TAG:Python部落 |