You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 02:24:05