Django实现表单提交限制:活动最多10人报名、单学生仅报1次
Django学生活动报名系统限制实现方案
以下实现从模型层、表单层、视图层三层做约束,既避免脏数据入库,也能给用户友好的操作提示:
1. 模型层改造(核心兜底约束)
首先补全原有代码中字段缺省的models.前缀,同时新增两个限制的兜底校验,防止脏数据直接写入数据库:
from django.db import models class Klas(models.Model): klas = models.CharField(max_length=8) def __str__(self): return f"{self.klas}" class Activiteit(models.Model): titel = models.CharField(max_length=64) docent = models.CharField(max_length=32) icon = models.ImageField() uitleg = models.TextField() def __str__(self): return f"{self.id}:{self.titel}:{self.docent}" # 可选优化:新增剩余名额属性,前端可直接展示 @property def remaining_slots(self): return 10 - self.aanmelden_set.count() class Aanmelden(models.Model): naam = models.CharField(max_length=32) # 加unique约束实现同一名学生仅能报名一次,同时自定义错误提示 studentnummer = models.IntegerField(unique=True, error_messages={"unique":"该学号已报名过活动"}) klas = models.ForeignKey(Klas, on_delete=models.CASCADE, default=None, blank=True) activiteit = models.ForeignKey(Activiteit, on_delete=models.CASCADE, default=None, blank=True) def save(self, *args, **kwargs): # 仅新增报名时校验活动人数,修改已有报名记录不需要触发 if not self.pk: current_signup_count = Aanmelden.objects.filter(activiteit=self.activiteit).count() if current_signup_count >= 10: raise ValueError("该活动报名人数已满") super().save(*args, **kwargs) def __str__(self): return f"{self.id}:{self.naam}:{self.studentnummer}"
2. 表单层改造(前置校验,友好提示)
重写表单的clean方法做前置校验,用户提交时就能直接看到对应字段的错误提示,不用等到请求到模型层才报错:
from django import forms from .models import Aanmelden class AanmeldenForm(forms.ModelForm): class Meta: model = Aanmelden fields = ('naam','studentnummer','klas','activiteit') def clean(self): cleaned_data = super().clean() studentnummer = cleaned_data.get("studentnummer") activiteit = cleaned_data.get("activiteit") # 校验学号是否已报名 if studentnummer and Aanmelden.objects.filter(studentnummer=studentnummer).exists(): self.add_error("studentnummer", "该学号已报名过活动,不可重复报名") # 校验所选活动是否已满员 if activiteit: current_count = Aanmelden.objects.filter(activiteit=activiteit).count() if current_count >= 10: self.add_error("activiteit", "当前活动报名人数已满,请选择其他活动") return cleaned_data
3. 视图层改造(异常兜底,避免服务报错)
新增异常捕获逻辑,即使并发场景下绕过表单校验,也不会直接抛出500错误:
from django.shortcuts import render from .models import Activiteit from .forms import AanmeldenForm def home(request): activiteiten = Activiteit.objects.all() form = AanmeldenForm() if request.method == 'POST': form = AanmeldenForm(request.POST) if form.is_valid(): try: form.save() # 可在此处接入Django Message组件实现报名成功提示 except ValueError as e: form.add_error(None, str(e)) return render(request, 'home.html', { 'activiteiten': activiteiten, 'form':form, })
可选高并发优化
如果报名活动并发量较高,可在保存逻辑外层加事务和行锁,彻底避免同时提交导致人数超标的问题:
from django.db import transaction # 视图层保存逻辑替换为以下代码 with transaction.atomic(): # 锁住当前活动的所有报名记录,避免并发写入 activiteit = cleaned_data.get("activiteit") Aanmelden.objects.select_for_update().filter(activiteit=activiteit).count() form.save()
内容的提问来源于stack exchange,提问作者Enmanuel V
相关产品推荐
相关产品推荐

