Django如何为Models中每个对象创建层级嵌套子条目?
解决方案
不需要为每一级子条目单独创建数据表,使用单表+自引用外键的设计即可实现任意深度的层级嵌套,完全匹配你的业务需求。
模型改造方法
在你原有Hw模型的基础上,新增一个指向模型自身的外键字段用来标记父节点,根节点的父字段留空即可。我顺手修正了你原模型里serianlnumber的拼写错误,修正后模型代码如下:
from django.db import models class Hw(models.Model): item = models.CharField(max_length=30, default='') version = models.CharField(max_length=30, default='') serial_number = models.CharField(max_length=30, default='') # 自关联父节点字段 parent = models.ForeignKey( 'self', on_delete=models.CASCADE, null=True, blank=True, related_name='children' )
字段说明:
on_delete=models.CASCADE代表父节点删除时,其下所有子节点会同步删除;如果需要父节点删除后保留子节点,可以改成models.SET_NULL即可related_name='children'配置后,可以直接通过当前节点对象取到所有直属子节点,不需要反向查外键
基础使用示例
1. 创建层级数据
按照父-子关系传入对应parent参数即可,嵌套层级没有数量限制:
# 创建根节点abc2 abc2 = Hw.objects.create( item='abc2', version='abc2V', serial_number='abc2S#', parent=None ) # 创建abc2的一级子项 abc2sub1 = Hw.objects.create( item='abc2sub1', version='abc2sub1V', serial_number='abc2sub1S#', parent=abc2 ) # 创建二级子项 abc2sub_sub1 = Hw.objects.create( item='abc2sub_sub1', version='abc2sub_sub1V', serial_number='abc2sub_sub1S#', parent=abc2sub1 ) # 创建另一个根节点abc3 abc3 = Hw.objects.create( item='abc3', version='abc3V', serial_number='abc3S#', parent=None )
2. 递归输出树形结构
和你给出的缩进示例一致的输出效果,可以通过简单递归实现:
def print_hw_tree(node_list, indent=0): # 打印表头 if indent == 0: print(f"{'Item':<18}{'Version':<18}{'S#'}") for node in node_list: # 按层级缩进输出 print(f"{' '*indent}{node.item:<18}{node.version:<18}{node.serial_number}") # 递归遍历当前节点的所有子节点 print_hw_tree(node.children.all(), indent + 2) # 先取出所有顶级根节点 root_nodes = Hw.objects.filter(parent__isnull=True) print_hw_tree(root_nodes)
运行后输出结果和你给出的结构示例完全匹配:
Item Version S# abc2 abc2V abc2S# abc2sub1 abc2sub1V abc2sub1S# abc2sub_sub1 abc2sub_sub1V abc2sub_sub1S# abc3 abc3V abc3S#
补充说明
- 这种设计的优势是只需要维护一张表,后续新增/修改字段只需要调整这一个模型,所有层级的条目通用一套逻辑,维护成本极低
- 如果你的业务场景层级非常深(超过20级)、查询量大,可以引入树形结构优化库来减少递归查询的性能损耗,常规硬件BOM类的业务场景用原生自关联完全够用,不需要额外引入依赖。
内容的提问来源于stack exchange,提问作者justhelpme
相关产品推荐
相关产品推荐

