2020-12-08 Django Migrations 初探

问题背景

在对django项目进行版本控制的时候,因为在编写app的某些阶段会涉及到一些manage=False的旧数据表,这时必须手动使用navicat/执行sql语句进行数据库迁移
这样一来导致一部分models使用migrations可以执行自动迁移,另一部分models则需要手动同步数据库,由于对django项目数据库迁移多人协作最佳的工作流程目前还不是很明确,以及不同models之间相互的引用耦合,在下拉更新后执行migrate的时候总会出现一些奇奇怪怪的依赖问题。这次希望通过重新构建以及整理一遍migrations的流程,探索一下在版本控制下的最佳的迁移流程。

问题一:如何重置migrations,让每个app的migrations的依赖关系更加明确

1. 查看当前迁移状态

python manage.py showmigrations
其中展示的信息为当前项目INSTALLED_APPS中所有的app的迁移文件的列表, 其中[X]代表已经migrate了的migration
优先列出项目内创建的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. 重置迁移状态

$ python manage.py runserver 确保程序在当前状态是可以执行的
如果报错则先对某些指定的app进行migrate$ python manage.py migrate 之后再进行下一步操作
$ python manage.py migrate --fake zero 将某个app的迁移状态全部标记为未执行,即把上面所有的[X]全部变为[ ]

3. 删除迁移文件

将所有的迁移文件删除

  • 对于项目内构建的app,默认位置在my_project//migrations/内,可以将整个migrations文件夹删除,或者建议用文件夹改名的方式之后如果报错还可以还原
    之后观察$ python manage.py showmigrations 在对应的app位置会显示没有任何migtrations
  • 对于第三方app,则在当前运行环境的site-packages//migrations/`内,可以将整个migrations文件夹删除,或者建议用文件夹改名的方式之后如果报错还可以还原

注: 引用的app的APP_NAME为实际app的名称,不需要加全地址,例如django.contrib.admin 的APP_NAME为 admin

4. 重新构建迁移文件

$ python manage.py makemigrations / $ python manage.py makemigrations
注: 引用的app的APP_NAME为实际app的名称,不需要加全地址,例如django.contrib.admin 的APP_NAME为 admin
对所有app进行构建之后变成这样:每个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/指定app第一条初始化的migration标记为[X],并不实际执行migration操作
$ python manage.py migrate --fake [] # 这条命令会将所每个app/指定app的所有migrations标记为[X],并不实际执行migration操作
参数备注: <...> 表示里面的内容为变量, 需要替换为实际的字符串, [...] 表示该参数可选可不选

Tips:

已经执行的迁移记录会被记录在settings.DATABASES, "default"alias定义的数据库connection里的django_migrations里,这个记录大致上就是showmigratons判断哪条migration需要标记[X]的依据,从而决定在migrate时需要执行哪些没有的
总的来说:

  • migrations files -> 位于不同app的位置,用于定义每个migration的详细操作
  • django_migrations数据库表记录 -> 标记migrations files哪些被执行了,以及执行时间,仅此而已

问题二:如何对引用外部app(非在项目内创建的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/

你可能感兴趣的:(2020-12-08 Django Migrations 初探)