如何限制TrainingPlan中TrainingUnit及TrainingUnit中Exercise的添加数量?
解决方案
一、限制单个TrainingPlan最多包含12个TrainingUnit
在TrainingUnit模型中添加验证逻辑,确保关联的训练计划下的单元总数不超过12。通过重写clean方法做校验,并在save时强制触发验证,避免直接调用save()绕过检查:
class TrainingUnit(models.Model): trainingplan = models.ForeignKey(TrainingPlan, on_delete=models.CASCADE) def clean(self): super().clean() # 统计当前训练计划下已有的单元数量 unit_count = TrainingUnit.objects.filter(trainingplan=self.trainingplan).count() # 新建单元时,检查总数是否即将超过12 if self.pk is None and unit_count >= 12: raise ValidationError("单个训练计划最多只能添加12个训练单元") def save(self, *args, **kwargs): self.full_clean() # 触发所有验证逻辑 super().save(*args, **kwargs)
二、限制单个TrainingUnit的Exercise数量在3-5之间
在Exercise模型中添加校验,确保训练单元下的动作数量符合3-5的要求,同时可选添加删除拦截,防止数量低于下限:
1. 添加动作时的上限校验
class Exercise(models.Model): trainingunit = models.ForeignKey(TrainingUnit, on_delete=models.CASCADE) exercisename = models.CharField(max_length=100, verbose_name="Exercise", choices=EXERCISE_CHOICES) exercisesets = models.IntegerField(choices=SETSCHOICES) exercisereps = models.IntegerField(choices=REPCHOICES) def clean(self): super().clean() exercise_count = Exercise.objects.filter(trainingunit=self.trainingunit).count() # 新建动作时,检查总数是否即将超过5 if self.pk is None and exercise_count >= 5: raise ValidationError("单个训练单元最多只能添加5个训练动作") def save(self, *args, **kwargs): self.full_clean() super().save(*args, **kwargs)
2. 防止动作数量低于3的删除拦截
如果需要确保训练单元始终至少有3个动作,可以通过pre_delete信号拦截非法删除:
from django.db.models.signals import pre_delete from django.dispatch import receiver from django.core.exceptions import ValidationError @receiver(pre_delete, sender=Exercise) def prevent_exercise_under_min(sender, instance, **kwargs): training_unit = instance.trainingunit # 计算删除后剩余的动作数量 remaining_count = Exercise.objects.filter(trainingunit=training_unit).count() - 1 if remaining_count < 3: raise ValidationError("单个训练单元至少需要保留3个训练动作,无法继续删除")
3. 可选:训练单元的下限校验
也可以在TrainingUnit模型中添加校验,确保保存时关联的动作数量不低于3:
class TrainingUnit(models.Model): trainingplan = models.ForeignKey(TrainingPlan, on_delete=models.CASCADE) def clean(self): super().clean() # 保留之前的训练计划数量校验逻辑 unit_count = TrainingUnit.objects.filter(trainingplan=self.trainingplan).count() if self.pk is None and unit_count >= 12: raise ValidationError("单个训练计划最多只能添加12个训练单元") # 新增动作数量下限校验 exercise_count = Exercise.objects.filter(trainingunit=self).count() if exercise_count < 3: raise ValidationError("单个训练单元至少需要添加3个训练动作") def save(self, *args, **kwargs): self.full_clean() super().save(*args, **kwargs)
注意事项
- 模型层的校验是后端的最后一道防线,能有效避免前端绕过限制的情况。
- 如果使用Django表单,可以在表单层同步添加校验逻辑,给用户更及时的前端提示。
- 所有
ValidationError的提示信息可以根据实际需求调整,让用户更容易理解。
内容的提问来源于stack exchange,提问作者Soulofcinder
相关产品推荐
相关产品推荐

