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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 00:15:49