如何在Django应用中限制匿名用户的表单提交请求
Django匿名访客表单提交次数限制实现方案
实现思路
匿名访客无法通过用户ID识别,因此采用客户端IP地址作为唯一标识,记录每次提交的时间戳,在提交时统计指定时间段内的提交次数,超过限制则拦截并提示。
1. 创建提交记录模型
首先在你的应用models.py中创建模型,用于存储访客IP和提交时间:
from django.db import models from django.utils import timezone class SubmissionRecord(models.Model): ip_address = models.CharField(max_length=45) # 兼容IPv6格式 submitted_at = models.DateTimeField(default=timezone.now) class Meta: # 添加索引提升查询效率 indexes = [ models.Index(fields=['ip_address', 'submitted_at']), ]
执行数据库迁移命令生效:
python manage.py makemigrations python manage.py migrate
2. 修改视图加入限制逻辑
更新你的视图代码,加入IP获取、次数统计和限制判断:
from django.shortcuts import render from django.utils import timezone from datetime import timedelta from .models import SubmissionRecord # 自定义限制参数 DAILY_SUBMIT_LIMIT = 10 MONTHLY_SUBMIT_LIMIT = 50 def homeview(request): context = {} # 获取访客真实IP(兼容反向代理场景) x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') ip_address = x_forwarded_for.split(',')[0].strip() if x_forwarded_for else request.META.get('REMOTE_ADDR', '') if request.method == "POST" and 'text1' in request.POST: now = timezone.now() # 计算当日、当月的起始时间 today_start = now.replace(hour=0, minute=0, second=0, microsecond=0) month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) # 统计当前IP的提交次数 daily_count = SubmissionRecord.objects.filter( ip_address=ip_address, submitted_at__gte=today_start ).count() monthly_count = SubmissionRecord.objects.filter( ip_address=ip_address, submitted_at__gte=month_start ).count() # 判断是否超出限制 if daily_count >= DAILY_SUBMIT_LIMIT or monthly_count >= MONTHLY_SUBMIT_LIMIT: context['error'] = "you have reached your daily or monthly limit!" else: # 正常处理表单提交 text1 = request.POST.get('text1') text2 = request.POST.get('text2') data = my_custom_function(text1, text2) context['data'] = data # 记录本次提交 SubmissionRecord.objects.create(ip_address=ip_address) return render(request, 'home.html', context)
3. 修改模板显示提示信息
在表单上方添加错误提示区域:
{% if error %} <div class="alert alert-danger">{{ error }}</div> {% endif %} <form action="" method="POST"> {% csrf_token %} <input class="form-control m-3 w-50 mx-auto" type="text" name="text1" id="text1" placeholder=""> <input class="form-control m-3 w-50 mx-auto" type="text" name="text2" id="text2" placeholder=""> <input class="btn btn-primary btn-lg my-3" type="submit" value="Submit"> </form>
补充说明
- 反向代理适配:如果部署在Nginx等反向代理后,需确保代理配置中传递
X-Forwarded-For请求头,否则会获取到代理服务器IP而非访客真实IP。 - 参数优化:可将限制次数配置到
settings.py中,方便统一管理。 - 数据清理:可通过Django定时任务(如Celery Beat)定期清理3个月以上的提交记录,避免数据库冗余。
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

