Django migrate 原理和规范

Django migrate规范

概述

Django的数据库相关的迁移操作,大体包括makemigrations和migrate两个步骤。

  1. 生成迁移文件
    修改models - 添加一个field或者删除一个model - 然后运行makemigrations:
$ python manage.py makemigrations
Migrations for 'books':
  books/migrations/0003_auto.py:
    - Alter field author on book

在所有迁移文件过程中,models将扫描并比较最近的版本文件,然后生成一系列新的migrations。然而这个迁移命令并不完美,有些复杂情况可能没有处理好导致迁移失败。最好,可以去检查下migrations,新的改变会不会导致冲突。

  1. 迁移数据
    一旦生成了新的迁移文件,为了迁移作用于数据库,应该执行以下指令:
$ python manage.py migrate
Operations to perform:
  Apply all migrations: books
Running migrations:
  Rendering model states... DONE
  Applying books.0003_auto... OK

还可以为migration(s),取个名字–name,并且可以指定某个app your_app_label:

$ python manage.py makemigrations --name changed_my_model your_app_label
  1. 查看迁移状态 - 在数据库中,已经生效的[X] ,还未生效的[ ]
F:\experiments\my_blog>python manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
my_app
 [X] 0001_initial
 [ ] 0002_article_tags
 [ ] 0003_reporter2
sessions
 [X] 0001_initial

原理

  • 文件夹migrations
├─apps
│  ├─my_app
│  │  ├─migrations                  # python manage.py makemigrations运行会生成以下文件
│  │  │  ├─0001_initial.py          # 如果文件夹没有migrations文件,第一次运行则生成左边文件
│  │  │  ├─0002_article_tags.py     # 之后每次运行makemigrations命令,都会一次递增生成migrations文件。命名方式:四位数_model名_属性名.py
│  │  │  ├─...
  • 代码内容0002_article_tags.py
from django.db import migrations, models


class Migration(migrations.Migration):
    # 依赖 域my_app中的'0001_initial.py',如果依赖文件不存在,会报错。
    dependencies = [
        ('my_app', '0001_initial'),
    ]
    # 数据库迁移操作,结合依赖:在原'0001_initial.py'基础上,新增field-'tags'
    operations = [
        migrations.AddField(
            model_name='article',
            name='tags',
            field=models.CharField(default='', max_length=30),
        ),
    ]
  • 数据库表django_migrations

每次python manage.py migrate,生效之前会在此表中查询执行到的步骤,生效之后迁移的migrations文件都会在此表中有记录
Django migrate 原理和规范_第1张图片

规范

  1. 数据库表已经有数据,新增字段需要设置默认数值
class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    # 新增属性,如下
    desc = models.CharField(max_length=300, default='')

如果没有,default=’’,默认数值设置,会有以下提示:

F:\experiments\my_blog>python manage.py makemigrations
You are trying to add a non-nullable field 'desc' to article without a default; we can't do that (the database needs something to populate existing ro
ws).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option:
  1. 由于团队多人开发,对负责的模块app,做好migrations文件的版本控制。避免出现迁移文件的丢失,导致migration dependencies节点缺失报错。
django.db.migrations.exceptions.NodeNotFoundError: Migration my_app.0002_article_desc dependencies reference nonexistent parent node ('my_app', '0001_
initial')

出现迁移文件的丢失,当然有一种方法是把所有迁移文件删除,重新生成,再migrate,但新增的修改不会migrate于数据库。原因是数据库版本控制和项目migrations失去同步。

F:\experiments\my_blog>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, my_app, sessions
Running migrations:
  No migrations to apply.

以下是数据库与本地项目migrations失去同步,挽救措施:

  1. 先不要将model修改代码添加进去,作为一个initial原点。
F:\experiments\my_blog>python manage.py makemigrations
Migrations for 'my_app':
  apps\my_app\migrations\0001_initial.py
    - Create model Article
    - Create model Reporter
    - Create model Reporter2
  1. 使用migrate --fake-initial参数,将刚刚生成的迁移脚本,标记为已经完成(因为这些模型相对应的表,其实都已经在数据库中存在了,不需要重复执行了。)
F:\experiments\my_blog>python manage.py migrate --fake-initial
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, my_app, sessions
Running migrations:
  No migrations to apply.
  1. 将model修改代码添加进去,之后操作不变化
python manage.py makemigrations

python manage.py migrate

参考

Django官网 - migrations

segmentfault - 重置Django migration的常见方式

csdn - django-关于manage.py migrate无效的问题

你可能感兴趣的:(django)