Django自定义迁移中删除Cancelled订单失效,普通文件可正常执行
Django迁移删除Cancelled订单失效的解决办法
问题根源
你的迁移代码里,删除Cancelled订单后又调用了order.save()——执行order.delete()已经把记录从数据库删掉了,但紧接着的save()会把这个实例重新插入回数据库,相当于白删了。而Pending/Completed状态的订单因为没执行删除,save()能正常保存修改,所以看起来只有删除操作失效。
快速修复
把order.save()移到非删除的分支里,避免删除后重新创建记录:
from datetime import timedelta from django.db import migrations def modify_delivery_warranty(apps, schema_editor): orders = apps.get_model("main_app", "Order") # 把QuerySet转为列表,防止遍历过程中数据变化导致的索引错位 all_orders = list(orders.objects.all()) # 倒序遍历(你原来的逻辑是对的,避免删除元素后影响后续遍历) for order in reversed(all_orders): if order.status == "Cancelled": order.delete() else: if order.status == "Pending": order.delivery = order.order_date + timedelta(days=3) elif order.status == "Completed": order.warranty = "24 months" # 只有非删除的订单才执行保存 order.save() # 修复反向迁移的问题:移除不可靠的全局变量,用正确的实例属性访问 def revert_modify_delivery_warranty(apps, schema_editor): orders = apps.get_model("main_app", "Order") # 恢复被修改的订单(这里的默认值请根据你的实际业务逻辑调整) for order in orders.objects.filter(status__in=["Pending", "Completed"]): if order.status == "Pending": order.delivery = None # 替换成你原来的delivery默认值 elif order.status == "Completed": order.warranty = "12 months" # 替换成你原来的保修期默认值 order.save() # 若需要恢复被删除的Cancelled订单,需在正向迁移时提前记录这些订单的数据 # 比如在正向函数中将删除的订单数据存入辅助表,反向时读取重建 class Migration(migrations.Migration): dependencies = [ ('main_app', '0021_order'), ] operations = [ migrations.RunPython( modify_delivery_warranty, reverse_code=revert_modify_delivery_warranty ) ]
额外注意事项
- 别在迁移里用全局变量:Django迁移的正向和反向函数可能在不同上下文执行,全局变量无法持久化数据,会导致反向迁移失败。如果需要保存反向迁移所需的数据,建议在正向函数中将数据存入数据库的辅助表。
- 避免直接遍历QuerySet修改/删除:把QuerySet转为列表(
list(orders.objects.all())),防止因为QuerySet的惰性求值特性,导致遍历过程中数据动态变化引发的异常。 - 反向迁移要谨慎:不要直接执行
orders.objects.all().delete(),这会删除所有订单,包括迁移前就存在的无关记录,必须精准恢复被修改和删除的数据。
内容的提问来源于stack exchange,提问作者Polishko
相关产品推荐
相关产品推荐

