如何在Django模型中存储数量不定的外键关联集合
Django 多外键集合存储方案
你遇到的是典型的关联表建模问题,不要在单个字段里用逗号分隔拼接多个外键ID,这种写法违反数据库设计范式,后续筛选、级联删除、关联查询都会非常难维护,根据你的业务场景选下面两种标准实现即可:
- 注意:你代码里的
DeviceClassificationGroup类漏写了models.Model继承,直接运行会报错,需要先补上。另外不建议手动定义id = models.IntegerField(primary_key=True),Django默认会自动生成自增主键,手动定义容易引发主键冲突问题。
场景1:单个分类仅能归属1个分类组(一对多)
如果你的业务规则是一个分类只能放在一个组里、一个组可以放任意多个分类,外键需要定义在「多」的一侧,也就是DeviceClassification表中,不需要在分组表加classification字段。
模型代码
ClassificationGroup.py修改后:
from django.db import models class DeviceClassificationGroup(models.Model): vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, null=True) name = models.CharField(max_length=100) description = models.CharField(max_length=1000)
Classification.py中新增外键字段:
class DeviceClassification(models.Model): vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, null=True) # 新增关联分组的外键 group = models.ForeignKey( DeviceClassificationGroup, on_delete=models.CASCADE, related_name="classifications", null=True, blank=True ) id = models.IntegerField(primary_key=True) name = models.CharField(max_length=100) description = models.CharField(max_length=1000) device_type = models.IntegerField() device_name_regex = models.CharField(max_length=100) vid_pid = models.CharField(max_length=50) device_instance_id = models.CharField(max_length=100) serial_number = models.CharField(max_length=100) brand = models.CharField(max_length=25) def __str__(self): return self.name
调用方式
通过外键的反向关联,就能直接拿到某个分组下的所有分类,数量没有限制:
# 获取id=1的分组实例 target_group = DeviceClassificationGroup.objects.get(id=1) # 取出该分组下全部分类,返回QuerySet集合,支持后续filter、count等操作 group_classifications = target_group.classifications.all()
场景2:单个分类可归属多个分类组(多对多)
如果业务允许一个分类同时被分到多个不同的组,直接在分组模型里用ManyToManyField替换你原来的classification = ??位置即可,Django会自动生成中间关联表维护对应关系,支持绑定任意数量的分类。
模型代码
ClassificationGroup.py修改后:
from django.db import models class DeviceClassificationGroup(models.Model): vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, null=True) id = models.IntegerField(primary_key=True) name = models.CharField(max_length=100) description = models.CharField(max_length=1000) # 多对多关联分类表 classifications = models.ManyToManyField( DeviceClassification, related_name="groups", blank=True )
Classification.py不需要做额外修改。
调用方式
target_group = DeviceClassificationGroup.objects.get(id=1) # 获取分组下全部分类 group_classifications = target_group.classifications.all() # 给分组批量绑定分类,支持传多个分类实例 target_group.classifications.add(classification_a, classification_b, classification_c) # 移除某个分类 target_group.classifications.remove(classification_a)
内容的提问来源于stack exchange,提问作者Mukul
相关产品推荐
相关产品推荐

