官术网_书友最值得收藏!

2.4.3 追蹤makemigrations命令

makemigrations命令對應(yīng)的代碼如下:

從上面的代碼可以看到,在makemigrations命令中,Command類直接繼承自BaseCommand類,所以它的執(zhí)行流程相對比較簡單,重點是Command類中的handle()方法。handle()方法的實現(xiàn)如下:

針對handle()方法,筆者整理了7處代碼進行講解:

第1處代碼非常簡單,得到MigrationLoader對象,在前面已多次使用過。

第2處代碼是檢測遷移文件之間的一致性。該代碼段中的aliases_to_check默認為['default']。這個列表中的元素實際上對應(yīng)著settings.py文件中DATABASES的key,而該key對應(yīng)的value值正是以字典形式保存的數(shù)據(jù)庫連接信息。在DATABASES中配置的數(shù)據(jù)庫連接信息會在一開始全部處理后保存在django.db.connections中,需要通過key來獲取相應(yīng)的數(shù)據(jù)庫連接信息,最后通過MigrationLoader對象的check_consistent_history(connection)方法檢測遷移文件之間的一致性。該方法會根據(jù)connection搜索該數(shù)據(jù)庫遷移表中的數(shù)據(jù)進行刞斷,具體的刞斷邏輯可以通過直接閱讀方法的源碼得到。第一次執(zhí)行makemigrations命令時,數(shù)據(jù)庫中的遷移表還未生成,沒有仸何遷移數(shù)據(jù),所以檢查直接通過。

第3處代碼是檢測遷移文件之間的沖突。detect_conflicts()方法的源碼如下:

從上面的代碼可以看到,當在同一應(yīng)用下存在多個屬于葉子節(jié)點的遷移文件時,會被檢測為沖突。下面看一個操作示例:

在上面的示例中,給shell_test應(yīng)用添加了2個遷移文件,并都加到MigrationLoader對象中。由于沒有添加依賴,所以在shell_test應(yīng)用下有2個葉子節(jié)點,會被檢測為沖突。在給('shell_test','00001_xxxxx)'添加內(nèi)部應(yīng)用依賴后,在每個應(yīng)用下只有1個葉子節(jié)點,不會被檢測為沖突。下面看本次命令追蹤的檢測沖突情冴:

從上面的結(jié)果可以看出,在Django中,默認應(yīng)用的遷移文件都不存在沖突。在筆者手工創(chuàng)建的shell_test應(yīng)用下只有一個遷移文件,也不存在沖突。

第4處代碼比較簡單,就是當檢測到有沖突且設(shè)置為不合并(merge=False)時,直接拋出異常。

第5處代碼也比較簡單,如果有沖突且設(shè)置了合并參數(shù),就對這些遷移文件進行合并處理。

第6處代碼是檢查應(yīng)用中的模型類與項目已有的遷移文件中保存的模型信息是否一致。這里是通過一個changes檢測機制得到相應(yīng)變化的。該檢測機制比較復(fù)雜,代碼量較大,本書后續(xù)不會直接分析該自動檢測類,而是觀察檢測結(jié)果,為后面分析遷移文件的生成代碼做準備。

第7處代碼是根據(jù)上一步得到的變化信息進行處理。如果沒有變化,提示No changes detected。如果有變化,調(diào)用write_migration_files()方法生成一個新的遷移文件。

通過上面的分析可以清楚地看到,遷移文件的生成需要2個條件:得到changes和調(diào)用write_migration_files()方法。為了演示changes的輸出,這里先初除shell_test應(yīng)用下的所有遷移數(shù)據(jù):

再手工生成MigrationAutodetector對象,并調(diào)用該對象的changes()方法獲取shell_test應(yīng)用下的遷移變化數(shù)據(jù):

從上面的代碼可以看到,當使用makemigrations命令給shell_test應(yīng)用生成遷移文件時,得到的changes為一個字典形式,每個key代表著對應(yīng)的應(yīng)用標簽,其value值為一個列表,列表的元素為Migration對象。這些Migration對象將被寫入對應(yīng)的遷移文件中。文件名既可以由外部指定,也可以由Django默認指定。最后看write_migration_files()方法,其源碼如下:

write_migration_files()方法通過循環(huán)遍歷changes來生成遷移文件,而遷移文件的內(nèi)容正是其中保存的Migration類。其中,MigrationWriter對象的as_string()方法可以將傳入的Migration對象轉(zhuǎn)成字符串形式。下面使用as_string()方法輸出上面得到的Migration對象:

上面輸出的結(jié)果正是第一次執(zhí)行makemigrations命令時得到的遷移文件內(nèi)容。下面給出一些簡單的操作示例,以幫助讀者更好地理解MigrationWriter類的功能:

在追蹤makemigrations命令的執(zhí)行過程中,最難的部分在于檢測當前模型類與已存在遷移文件中的模型類的變化部分(即得到changes值),而這一工作最終是由MigrationAutodetector對象的changes()方法來承擔的。至此,我們已基本掌握了makemigrations命令。

主站蜘蛛池模板: 伊吾县| 阿城市| 浦城县| 旬阳县| 英吉沙县| 德阳市| 利川市| 松江区| 辽源市| 呼和浩特市| 郁南县| 金华市| 专栏| 扶绥县| 陵川县| 马龙县| 清丰县| 丰宁| 炉霍县| 通河县| 绥滨县| 巴青县| 吴忠市| 佳木斯市| 广西| 阿克| 涞源县| 始兴县| 黄龙县| 吕梁市| 若尔盖县| 绥德县| 延安市| 石河子市| 临城县| 梅州市| 襄樊市| 博爱县| 神农架林区| 云安县| 汤阴县|