Django如何为数据表设置学生、代理人两类可选所属人及字段选型?
方案可行性说明
你提到的新增employee OneToOne字段的方案是可以跑通的,但存在扩展性不足的问题,具体选择哪种实现方式取决于你的业务逻辑。
方案1:直接新增关联字段(适合业务不会再新增其他提交人类型的场景)
- 首先明确字段类型选择逻辑:
- 如果你的业务规则是每个学生/每个代理人最多只能提交1份申请,那用
OneToOneField是符合需求的 - 如果允许同一个学生/代理人提交多份申请,那需要把原有的
owner字段和新增的employee字段都改成ForeignKey
- 如果你的业务规则是每个学生/每个代理人最多只能提交1份申请,那用
- 实现注意事项:
- 两个关联字段都需要设置
null=True、blank=True,确保单条申请只会关联一个提交人 - 新增提交人类型字段方便快速区分数据来源,同时增加模型校验避免两个关联字段同时赋值/同时为空:
- 两个关联字段都需要设置
from django.core.exceptions import ValidationError class Application: SUBMITTER_TYPE_CHOICES = ( ('student', '学生'), ('agent', '代理人'), ) submitter_type = models.CharField(max_length=16, choices=SUBMITTER_TYPE_CHOICES) owner = models.OneToOneField(Student, on_delete=models.CASCADE, null=True, blank=True) employee = models.OneToOneField(Employee, on_delete=models.CASCADE, null=True, blank=True) name = models.CharField(max_length=64) dob = models.CharField(max_length=64) def clean(self): # 校验必须且只能关联一个提交人 if (self.owner is None and self.employee is None) or (self.owner is not None and self.employee is not None): raise ValidationError('申请必须且只能关联一个提交人')
- 数据查询逻辑:筛选学生提交的申请用
Application.objects.filter(submitter_type='student'),筛选代理人提交的用Application.objects.filter(submitter_type='agent')即可
方案2:通用外键方案(适合后续可能新增其他提交人类型的场景)
如果后续还有可能增加比如学校管理员、第三方机构等提交申请的需求,推荐使用Django内置的ContentType框架实现通用关联,无需每次新增提交人类型都修改Application模型:
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models class Application: # 基础字段 name = models.CharField(max_length=64) dob = models.CharField(max_length=64) # 通用关联字段 submitter_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) submitter_id = models.PositiveIntegerField() submitter = GenericForeignKey('submitter_type', 'submitter_id') # 如果需要限制每个提交人只能提交1份申请,增加如下唯一约束 class Meta: unique_together = ('submitter_type', 'submitter_id')
数据操作逻辑:
- 存储时直接给
submitter赋值对应的学生/代理人实例即可,框架会自动处理类型和ID的存储 - 查询所有学生提交的申请:
Application.objects.filter(submitter_type=ContentType.objects.get_for_model(Student)) - 查询指定学生提交的申请:
student_obj.application_set.all()(反向查询) - 代理人相关查询逻辑同上,替换对应的模型即可
内容的提问来源于stack exchange,提问作者sixovov947
相关产品推荐
相关产品推荐

