
在 Django CRM 系统中,直接删除被估计单、服务报告或发票引用的库存项会导致外键关联失效和页面崩溃;正确做法是通过 on_delete 参数配置外键行为(如 SET_NULL),使历史记录保留完整性,同时逻辑上“下架”库存项。
在 django crm 系统中,直接删除被估计单、服务报告或发票引用的库存项会导致外键关联失效和页面崩溃;正确做法是通过 `on_delete` 参数配置外键行为(如 `set_null`),使历史记录保留完整性,同时逻辑上“下架”库存项。
在 Django 中,库存项(InventoryItem)被其他模型(如 Estimate、ServiceReport、Invoice)通过 ForeignKey 引用时,数据库级的外键约束会强制维护参照完整性。默认若使用 models.CASCADE,删除库存项将连带删除所有关联报告——这显然不可取;而若未显式指定 on_delete(Django 2.0+ 已强制要求),则会引发 RuntimeError。
✅ 推荐解决方案:使用 on_delete=models.SET_NULL
该策略允许你“软性移除”库存项——即保留历史报告完整可读,仅将已删除项的外键字段设为 NULL,前提是该字段允许为空:
# models.py
from django.db import models
class InventoryItem(models.Model):
name = models.CharField(max_length=100)
sku = models.CharField(max_length=50, unique=True)
is_active = models.BooleanField(default=True) # 新增状态标识,便于前端过滤
def __str__(self):
return self.name
class Estimate(models.Model):
customer_name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
# 关键修改:允许 NULL + 指定 on_delete 行为
inventory_item = models.ForeignKey(
InventoryItem,
on_delete=models.SET_NULL, # 删除 InventoryItem 时,此字段置为 NULL
null=True, # 必须设为 True,否则无法存 NULL
blank=True, # 表单中可为空(可选)
related_name='estimates'
)
⚠️ 注意事项与最佳实践:
迁移前备份数据库:执行 python manage.py makemigrations && python manage.py migrate 前,请务必备份 db.sqlite3(例如复制为 db.sqlite3.backup)。
补充 is_active 字段:推荐为 InventoryItem 添加布尔字段(如 is_active),前端列表仅展示活跃项,避免误删;删除操作改为 item.is_active = False; item.save(),彻底规避外键问题。
Django Unfold下载提供使用 django-unfold (v0.56+) 构建高级 Django 管理界面的专业指导。当用户提及 django-unfold、unfold admin 等内容时使用此技能。
-
查询兼容性处理:模板或视图中需容错显示 NULL 外键,例如:
<!-- 在 report_detail.html 中 --> <td>{{ estimate.inventory_item.name|default:"[已下架]" }}</td> 避免 DO_NOTHING:虽技术上可行,但绕过 Django ORM 约束易导致数据库不一致,且 SQLite 不支持 ON DELETE DO NOTHING 的 DDL,强烈不推荐。
-
批量清理建议:若已有因 CASCADE 或缺失 on_delete 导致的损坏数据,可先用 Django Shell 修复外键为空:
# python manage.py shell from myapp.models import Estimate Estimate.objects.filter(inventory_item__isnull=False).exclude(inventory_item__is_active=True).update(inventory_item=None)
总结:真正的数据安全删除 ≠ 物理移除,而是语义隔离。通过 SET_NULL + is_active 双机制,既能满足业务上“下架库存”的需求,又能保障所有历史报告稳定加载、准确呈现,兼顾数据完整性与系统健壮性。










