第三站练习答案
python
# 模型增量
from django.core.validators import MaxValueValidator, MinValueValidator
priority = models.PositiveSmallIntegerField(
default=3,
validators=[MinValueValidator(1), MaxValueValidator(5)],
)验证器改善表单和 full_clean() 体验;数据库保证还需要 CheckConstraint(condition=Q(priority__range=(1, 5)), ...)。
python
# 数据迁移函数示意
def set_existing_priority(apps, schema_editor):
Ticket = apps.get_model("tickets", "Ticket")
Ticket.objects.filter(priority__isnull=True).update(priority=3)
def unset_priority(apps, schema_editor):
Ticket = apps.get_model("tickets", "Ticket")
Ticket.objects.update(priority=None)迁移中使用 apps.get_model() 获取历史模型,不直接导入当前 tickets.models.Ticket。
bash
python manage.py makemigrations
python manage.py sqlmigrate tickets 0002
python manage.py migrate
python manage.py makemigrations --check --dry-run专题二核对
- 新增一个临时布尔列标记“由本次迁移填充”的行,反向迁移只还原这些行;完成兼容窗口后再删除标记列。
- 百万行回填按主键游标分批,记录末尾主键、耗时、锁等待和失败数;批次可重入并在主从延迟超预算时暂停。
- 用户模型牵涉外键、M2M 中间表、权限和
ContentType;中途替换需要显式数据搬迁与依赖顺序,不能只重命名表。
深水边界
回滚数据迁移只有在信息仍可恢复时才真实可逆。把多个旧值合并成一个新值后,反向函数无法猜回原值;此时应明确使用前进修复或先保存映射。
开放练习(不提供答案)
设计一次将 title 拆成 summary 与 description 的零停机迁移,写出扩展、回填、切换、收缩四个发布批次。
加码题解:约束与数据迁移
python
from django.db import migrations
def fill_currency(apps, schema_editor):
Order = apps.get_model('orders', 'Order')
Order.objects.filter(currency__isnull=True).update(currency='CNY')
class Migration(migrations.Migration):
operations = [migrations.RunPython(fill_currency, migrations.RunPython.noop)]关键推理
数据迁移使用历史模型,先填充可空字段,再在下一次迁移收紧约束。
可替代方案
大表按主键分批更新并监控复制延迟,避免一次 UPDATE 长时间占锁。
典型错误
在迁移里直接 import 当前 Model,未来模型变化后旧迁移失去可重复性。
复盘时请把状态码/事务/权限/资源清理中的至少一项写成自动化测试,而不是只截图成功页面。