Django2.2中迁移(makemigrations和migrate)的原理和撤销回退操作图文详解

本文深入解析Django中ORM如何将Python模型转换为数据库表,以及如何通过迁移功能记录和执行数据库表结构的增量变更,包括迁移的原理、操作步骤及错误回退。

Django通过ORM来操作数据库,而其中数据库表结构的创建和变更因为尤其重要所以Django需要对其每一次的操作都进行记录和留档,以实现每次只执行增量变更,同时方便回溯和回退。Django中专门负责这一记录功能的模块叫迁移(migrate)。这一篇我们一起来看看迁移的原理和操作步骤,以及出错时的回退。

我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。

迁移的原理

模型类

所谓ORM就是将面向对象的python操作转变为数据库可识别的SQL语句,而数据库中每张表对应着Django中的一个模型类,也就是在models.py中定义的一个class。所以创建一张张SQL表也就变成了定义一个个模型类,而修改表结构也就变成了修改类属性,这是理解MTV中M,也就是models的核心思想。

例如下面是models.py中定义的三个类,分别是PeopleAmericanChinese。这里的People是另两个的父类,不过这里可以忽略

class People(models.Model):
    p_name = models.CharField(max_length=16)
    p_sex = models.BooleanField(default=True)


class American(People):
    a_state = models.CharField(max_length=16)


class Chinese(People):
    c_province = models.CharField(max_length=16)

完成了ORM映射,就变成了数据库里面的三张表。这里表名带的Four前缀是应用的名字,不用管
1-model.png

增量操作

一个models.py中写着所有的模型类,每一次对单个类做的微小的修改,不可能让所有表都跟着再做一次SQL操作,所以务必得是增量操作。

Django项目里的每一个应用都自带一个migrations目录,每次执行跟表结构变更相关的操作,都会在这里生成增量的操作文件,这些文件叫做迁移文件。

例如上面定义了三个类,在执行生成迁移文件操作之后,新增了下面这个文件
2-migrations.png

文件内容如下

class Migration(migrations.Migration):

    dependencies = [
        ('Four', '0003_auto_20200401_2321'),
    ]

    operations = [
        migrations.CreateModel(
            name='People',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('p_name', models.CharField(max_length=16)),
                ('p_sex', models.BooleanField(default=True)),
            ],
        ),
        migrations.CreateModel(
            name='American',
            fields=[
                ('people_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='Four.People')),
                ('a_state', models.CharField(max_length=16)),
            ],
            bases=('Four.people',),
        ),
        migrations.CreateModel(
            name='Chinese',
            fields=[
                ('people_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='Four.People')),
                ('c_province', models.CharField(max_length=16)),
            ],
            bases=('Four.people',),
        ),
    ]

注意其中的这一部分

dependencies = [
    ('Four', '0003_auto_20200401_2321'),
]

这就是本次执行的上一次执行,也就是说等0003_auto_20200401_2321这个迁移文件中的操作完成以后再执行本文件中的操作。

执行时序

从上面可以看出,migrations目录中的众多迁移文件对应着一批批的操作,这些文件被按照时间顺序先后执行就完成了最终的结果。

那么Django怎么知道某一个文件有没有被执行过呢?

这个也很简单,对每一次完成的操作记录一下时间就可以了。这些操作都被记录在项目自带的django_migrations表中。打开django_migrations表看一下
3-table.png
可以看到对于应用Four一共执行过四次操作,最后一次操作就是我们刚才创建三个表的0004_american_chinese_people文件。

迁移的步骤

有了上面的原理做为铺垫,梳理出迁移的操作步骤就不难了。

  1. 首先在models.py中创建或者修改模型类
  2. python manager.py makemigrations创建本次修改的迁移文件,此时会去数据库中查找上一次执行的文件并记录在本文件中
  3. 然后执行python manager.py migrate执行迁移,将变更同步到数据库中

迁移的回退

假如某次操作涉及的操作太细碎,迁移后的效果不理想,最好的办法就是回退到上一次迁移的时候。

Django为我们创建了快捷的回退操作,直接对前一步的迁移文件重新手动迁移一次即可完成回退操作。

以上面创建三个表为例,直接再跑python manage.py migrate Four 0003_auto_20200401_2321即可。记得带上Four这个应用名

[fuhx@testmachine DjangoModel]$ python manage.py migrate Four 0003_auto_20200401_2321
Operations to perform:
  Target specific migration: 0003_auto_20200401_2321, from Four
Running migrations:
  Rendering model states... DONE
  Unapplying Four.0004_american_chinese_people... OK

之后会发现数据库中的三张表被自动删除了,同时django_migrations表中最后一条记录也没了
4-fallback.png

之后别忘了手动删除migrations目录中的0004号迁移文件,从而完成回退动作。

<think>我们正在讨论Django的数据库迁移问题。用户希望知道是否可以在Django中一次性完成所有数据库迁移操作,而不是多次执行makemigrationsmigrate。 根据Django迁移机制,通常我们需要分两步进行: 1. 生成迁移文件:`python manage.py makemigrations` 2. 应用迁移:`python manage.py migrate` 但是,用户希望一次性完成这两个步骤。Django本身并没有一个单一的命令可以同时完成makemigrationsmigrate。然而,我们可以通过编写自定义的管理命令或者使用shell脚本来实现一次性执行。 另外,参考引用[1][2]中提到从south迁移django migration的过程,其中包含了多个步骤,但也不是一个命令完成。 但是,我们可以通过以下方式实现“一次性”执行: 方案1:使用shell命令组合 在类Unix系统(Linux/macOS)中,可以使用: ```bash python manage.py makemigrations && python manage.py migrate ``` 在Windows中,可以使用: ```bash python manage.py makemigrations & python manage.py migrate ``` 方案2:创建自定义管理命令 我们可以创建一个自定义管理命令,例如叫做`migrate_all`,在这个命令中依次调用`makemigrations``migrate`。 步骤: 1. 在某个app的management/commands目录下创建文件,例如`migrate_all.py`。 2. 在该文件中编写命令代码: ```python from django.core.management.base import BaseCommand from django.core.management import call_command class Command(BaseCommand): help = 'Run makemigrations and migrate in one command' def handle(self, *args, **options): # 先执行makemigrations call_command('makemigrations') # 再执行migrate call_command('migrate') ``` 然后就可以通过以下命令一次性执行: ```bash python manage.py migrate_all ``` 注意:这种方式虽然可以一次性执行,但需要谨慎,因为makemigrations可能会生成多个迁移文件,而migrate会应用所有未应用的迁移。在生产环境中,我们通常希望分开执行以便审查迁移文件。 方案3:使用Django迁移参数 在某些情况下,我们可以使用`migrate --run-syncdb`,但这并不是用来替代makemigrations的,它只是用于创建所有模型的基础表(不涉及迁移历史),通常用于新项目初始化。 结论: Django本身不提供单一命令同时完成makemigrationsmigrate,但我们可以通过组合命令或自定义命令来实现。 另外,需要注意的是,引用[5]中提到了执行迁移时可能遇到的错误(ORA-00955),这通常是因为数据库对象已经存在。因此,在迁移过程中,如果出现错误,需要根据错误信息进行排查。 因此,回答用户问题:Django本身不支持一个命令同时完成makemigrationsmigrate,但可以通过上述方法实现一次性执行。 同时,我们也可以生成相关问题,以帮助用户更深入地理解迁移过程。 注意:在回答中,我们引用了站内引用,需要在末尾添加引用标识。</think>在 Django 中,**没有单一命令能同时完成 `makemigrations` `migrate` 两个操作**,因为它们是设计为分离的步骤,各有明确职责: ### 迁移流程解析 1. **`makemigrations`** 扫描模型变更并生成迁移文件(存储在 `app/migrations/` 目录),**不操作数据库** ```bash python manage.py makemigrations ``` 2. **`migrate`** 将迁移文件应用到数据库,并更新 `django_migrations` 表记录 ```bash python manage.py migrate ``` --- ### 实现"一次性迁移"的变通方案 #### 方案1:Shell 命令组合(推荐) ```bash # Linux/macOS python manage.py makemigrations && python manage.py migrate # Windows python manage.py makemigrations & python manage.py migrate ``` - ✅ 优势:单行命令完成全部操作 - ⚠️ 注意:需确保所有模型变更已正确配置 #### 方案2:自定义管理命令 1. 创建 `core/management/commands/migrate_all.py`: ```python from django.core.management.base import BaseCommand from django.core.management import call_command class Command(BaseCommand): help = '执行完整的数据库迁移流程' def handle(self, *args, **options): call_command('makemigrations') call_command('migrate') self.stdout.write(self.style.SUCCESS('✅ 数据库迁移完成')) ``` 2. 执行命令: ```bash python manage.py migrate_all ``` --- ### 重要注意事项 1. **迁移顺序依赖** 当多个应用存在跨应用依赖时,需按依赖顺序执行: ```bash python manage.py makemigrations app1 app2 && python manage.py migrate ``` 2. **生产环境警告** - 禁止直接在生产环境使用组合命令 - 必须先审查生成的迁移文件(`app/migrations/000X_*.py`) - 典型流程: ```mermaid graph LR A[本地开发] --> B[生成迁移文件] B --> C[代码审查] C --> D[测试环境验证] D --> E[生产环境应用] ``` 3. **迁移冲突处理** 若遇 `ORA-00955` 等错误(如表已存在): ```bash python manage.py migrate --fake # 标记为已应用[^5] ``` --- ### 为什么需要分离操作? | 步骤 | 作用 | 是否操作数据库 | |------|------|----------------| | `makemigrations` | 生成模型变更脚本 | ❌ 否 | | `migrate` | 执行SQL变更并记录状态 | ✅ 是 | 这种分离设计确保: 1. 迁移文件可版本控制 2. 支持多环境一致部署 3. 允许人工审核SQL语句[^4] --- ### 相关问题 1. 如何安全地在生产环境回滚Django数据库迁移2. `migrate --fake` `migrate --fake-initial` 有何本质区别? 3.Django提示"Table already exists"错误时应如何解决?[^5] 4. 如何批量为多个Django应用生成迁移文件? 5. 迁移文件冲突时如何解决 `InconsistentMigrationHistory` 错误?[^1][^3]
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值