Django中Student、University双模型多对多关联申请场景高效实现方案咨询
Django申请模型选型及实现方案
选型结论
优先选择方案1(独立Application模型作为多对多关联的中间表),完全不推荐方案2,该方案完全满足百万级数据的性能要求,也适配后续业务迭代需求。
方案2不可行的原因
方案2本质是使用Django默认的隐式多对多中间表,存在两个致命问题:
- 扩展性为0:默认中间表仅存储
student_id和university_id两个关联字段,无法存储申请时间、申请状态、提交材料、审核结果等业务必要字段,后续根本无法支撑业务需求 - 性能不达标:默认隐式中间表不支持自定义索引,百万级数据下双向查询需要跨表关联,查询效率极低,完全无法满足性能要求
- 双向查询不灵活:比如要查询某大学收到的待审核申请,需要反向关联Student表后再做过滤,查询开销远高于直接查申请表
独立Application表的效率说明
你担心的独立表效率问题完全不存在:
- 百万级数据量的单表查询,只要配置合理的索引,延迟可以稳定控制在毫秒级,远高于关联多表查询的效率
- 独立表支持针对业务查询场景自定义索引、约束,完全可以适配你的性能要求
- 后续业务迭代成本极低:如果要细化到申请大学的具体课程,仅需在Application表中新增Course外键即可,不需要改动原有模型结构
具体实现代码示例
from django.db import models from django.utils import timezone class University(models.Model): name = models.CharField(max_length=100) # 原有字段保留 class Student(models.Model): name = models.CharField(max_length=50) # 原有字段保留 # 通过through参数指定自定义中间表关联多对多关系 applied_universities = models.ManyToManyField( University, through='Application', related_name='applicants' ) class Application(models.Model): # 申请状态枚举,可根据业务需要扩展 STATUS_CHOICES = [ ('pending', '待审核'), ('accepted', '已录取'), ('rejected', '已拒绝'), ('cancelled', '已取消'), ] student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='applications') university = models.ForeignKey(University, on_delete=models.CASCADE, related_name='applications') apply_time = models.DateTimeField(default=timezone.now) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') # 可根据业务需要新增任意字段:申请材料路径、审核时间、备注等 material_file = models.FileField(upload_to='application_materials/', null=True, blank=True) audit_time = models.DateTimeField(null=True, blank=True) class Meta: # 针对常用查询场景配置索引,大幅提升百万级数据的查询效率 indexes = [ # 适配学生查询自己的申请记录的场景:按学生ID+申请时间倒序 models.Index(fields=['student', '-apply_time']), # 适配大学查询收到的申请的场景:按大学ID+申请状态+申请时间倒序 models.Index(fields=['university', 'status', '-apply_time']), # 可选唯一约束:避免同一个学生对同一个大学重复提交待审核申请 models.UniqueConstraint(fields=['student', 'university'], condition=models.Q(status='pending'), name='unique_pending_apply') ]
双向查询示例(满足学生、大学双方访问需求)
- 学生查询自己的所有待审核申请:
student.applications.filter(status='pending').order_by('-apply_time') - 大学查询收到的所有已录取申请:
university.applications.filter(status='accepted').order_by('-apply_time') - 查询某学生申请某大学的具体申请记录:
Application.objects.get(student=xxx, university=xxx)
所有查询均可直接基于申请表的字段过滤,无需额外跨表关联,性能最优。
内容的提问来源于stack exchange,提问作者sixovov947
相关产品推荐
相关产品推荐

