問題背景
在對django項目進行版本控制的時候,因為在編寫app的某些階段會涉及到一些manage=False的舊數(shù)據(jù)表,這時必須手動使用navicat/執(zhí)行sql語句進行數(shù)據(jù)庫遷移
這樣一來導致一部分models使用migrations可以執(zhí)行自動遷移,另一部分models則需要手動同步數(shù)據(jù)庫,由于對django項目數(shù)據(jù)庫遷移多人協(xié)作最佳的工作流程目前還不是很明確,以及不同models之間相互的引用耦合,在下拉更新后執(zhí)行migrate的時候總會出現(xiàn)一些奇奇怪怪的依賴問題。這次希望通過重新構(gòu)建以及整理一遍migrations的流程,探索一下在版本控制下的最佳的遷移流程。
問題一:如何重置migrations,讓每個app的migrations的依賴關(guān)系更加明確
1. 查看當前遷移狀態(tài)
python manage.py showmigrations
其中展示的信息為當前項目INSTALLED_APPS中所有的app的遷移文件的列表, 其中[X]代表已經(jīng)migrate了的migration
優(yōu)先列出項目內(nèi)創(chuàng)建的app的migrations(字母順序) ,其次列出引用外部的app的migrations(字母順序)
# my_project/my_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken', # TOKEN 驗證
'django_filters', # 查詢
'django_celery_results', # Celery result backend
'django_celery_beat', # Celery beat
'my_app_1',
'my_app_2',
]
$ python manage.py showmigrations
my_app_1
[X] 0001_initial
[X] 0002_some_migrations
[ ] 0003_some_migrations
[ ] 0004_some_migrations
[ ] 0005_some_migrations
my_app_2
[X] 0001_initial
[X] 0002_some_migrations
[X] 0003_some_migrations
[ ] 0004_some_migrations
admin
[X] 0001_initial
auth
[X] 0001_initial
authtoken
[X] 0001_initial
contenttypes
[X] 0001_initial
django_celery_beat
[X] 0001_initial
django_celery_results
[X] 0001_initial
sessions
[X] 0001_initial
2. 重置遷移狀態(tài)
$ python manage.py runserver 確保程序在當前狀態(tài)是可以執(zhí)行的
如果報錯則先對某些指定的app進行migrate$ python manage.py migrate <APP_NAME>之后再進行下一步操作
$ python manage.py migrate --fake <APP_NAME> zero 將某個app的遷移狀態(tài)全部標記為未執(zhí)行,即把上面所有的[X]全部變?yōu)?code>[ ]
3. 刪除遷移文件
將所有的遷移文件刪除
- 對于項目內(nèi)構(gòu)建的app,默認位置在
my_project/<APP_NAME>/migrations/內(nèi),可以將整個migrations文件夾刪除,或者建議用文件夾改名的方式之后如果報錯還可以還原
之后觀察$ python manage.py showmigrations在對應(yīng)的app位置會顯示沒有任何migtrations - 對于第三方app,則在當前運行環(huán)境的site-packages/<APP_FULL_PATH>/migrations/`內(nèi),可以將整個migrations文件夾刪除,或者建議用文件夾改名的方式之后如果報錯還可以還原
注: 引用的app的APP_NAME為實際app的名稱,不需要加全地址,例如django.contrib.admin 的APP_NAME為 admin
4. 重新構(gòu)建遷移文件
$ python manage.py makemigrations / $ python manage.py makemigrations <APP_NAME>
注: 引用的app的APP_NAME為實際app的名稱,不需要加全地址,例如django.contrib.admin 的APP_NAME為 admin
對所有app進行構(gòu)建之后變成這樣:每個app只有一個initial的migration,舒服了!
$ python manage.py showmigrations
my_app_1
[ ] 0001_initial
my_app_2
[ ] 0001_initial
admin
[ ] 0001_initial
auth
[ ] 0001_initial
authtoken
[ ] 0001_initial
contenttypes
[ ] 0001_initial
django_celery_beat
[ ] 0001_initial
django_celery_results
[ ] 0001_initial
sessions
[ ] 0001_initial
5. 偽造遷移記錄
$ python manage.py migrate --fake-initial [<APP_NAME>] # 這條命令只會將每個app/指定app第一條初始化的migration標記為[X],并不實際執(zhí)行migration操作
$ python manage.py migrate --fake [<APP_NAME>] # 這條命令會將所每個app/指定app的所有migrations標記為[X],并不實際執(zhí)行migration操作
參數(shù)備注: <...> 表示里面的內(nèi)容為變量, 需要替換為實際的字符串, [...] 表示該參數(shù)可選可不選
Tips:
已經(jīng)執(zhí)行的遷移記錄會被記錄在settings.DATABASES, "default"alias定義的數(shù)據(jù)庫connection里的django_migrations里,這個記錄大致上就是showmigratons判斷哪條migration需要標記[X]的依據(jù),從而決定在migrate時需要執(zhí)行哪些沒有的
總的來說:
- migrations files -> 位于不同app的位置,用于定義每個migration的詳細操作
- django_migrations數(shù)據(jù)庫表記錄 -> 標記migrations files哪些被執(zhí)行了,以及執(zhí)行時間,僅此而已
問題二:如何對引用外部app(非在項目內(nèi)創(chuàng)建的app)的migrations進行版本控制
TODO
參考
How to Reset Migrations
How to store third party apps migrations in django
官方文檔 settings.MIGRATION_MODULES
TODO:
簡化對managed=False的Model的測試流程:
https://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/
系列教程: Django Migrations詳細解釋
https://realpython.com/django-migrations-a-primer/