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

如何为Wagtail的InfoPage页面设置访问速率限制?

在Wagtail中为InfoPage设置访问速率限制的方案

方法1:直接给Page模型的serve方法添加ratelimit装饰器

这种方式最直接,仅针对单个页面模型生效。只需在你的InfoPage类中重写serve方法并加上原有的@ratelimit装饰器:

from ratelimit.decorators import ratelimit
from wagtail.models import Page
from django.db import models
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel

class InfoPage(Page):
    template = "wagtail/info_page.html"
    last_modified_date = models.DateField("Last modified date")
    body = RichTextField(features=['bold', 'italic', 'link', 'ul', 'h3'])

    content_panels = Page.content_panels + [
        FieldPanel('last_modified_date'),
        FieldPanel('body')
    ]
    
    parent_page_types = ['news.Index']
    subpage_types = []

    @ratelimit(key='ip', rate='15/m', block=True)
    def serve(self, request, *args, **kwargs):
        return super().serve(request, *args, **kwargs)

装饰器会直接作用于页面的请求处理逻辑,达到和原Django视图完全一致的限制效果。

方法2:使用自定义中间件批量限制

如果需要给多个页面类型统一添加速率限制,中间件是更高效的选择。创建一个自定义中间件,自动检查请求对应的页面类型并应用限制:

  1. 在项目目录下创建middleware.py文件,写入以下代码:
from ratelimit.core import is_ratelimited
from ratelimit.exceptions import Ratelimited
from django.http import HttpResponseForbidden
from wagtail.models import Page
from .models import InfoPage

class InfoPageRateLimitMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        try:
            # 获取当前请求对应的具体页面实例
            page = Page.objects.get(url_path=request.path).specific
            if isinstance(page, InfoPage):
                # 检查并应用速率限制
                ratelimited = is_ratelimited(
                    request=request,
                    key='ip',
                    rate='15/m',
                    increment=True,
                )
                if ratelimited:
                    raise Ratelimited()
        except Page.DoesNotExist:
            # 非Wagtail页面请求,直接跳过
            pass

        response = self.get_response(request)
        return response

    def process_exception(self, request, exception):
        # 捕获速率限制异常,返回403响应
        if isinstance(exception, Ratelimited):
            return HttpResponseForbidden("请求过于频繁,请稍后再试")
  1. 在settings.py的MIDDLEWARE列表中添加这个中间件:
MIDDLEWARE = [
    # 其他已存在的中间件...
    'your_project_name.middleware.InfoPageRateLimitMiddleware',
]

方法3:利用Wagtail的before_serve_page钩子

Wagtail提供了页面渲染前的钩子,可以在不修改模型或中间件的前提下,插入速率限制逻辑:

在项目的wagtail_hooks.py文件中添加以下代码:

from wagtail.core import hooks
from ratelimit.core import is_ratelimited
from django.http import HttpResponseForbidden
from .models import InfoPage

@hooks.register('before_serve_page')
def rate_limit_info_pages(page, request, serve_args, serve_kwargs):
    # 仅对InfoPage类型的页面应用限制
    if isinstance(page, InfoPage):
        ratelimited = is_ratelimited(
            request=request,
            key='ip',
            rate='15/m',
            increment=True,
        )
        if ratelimited:
            return HttpResponseForbidden("请求过于频繁,请稍后再试")
    # 返回None表示继续执行原有渲染逻辑
    return None

通用注意事项

确保你原有的Redis缓存配置仍然生效,django-ratelimit需要依赖缓存存储限制记录,在settings.py中确认:

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}

# 指定ratelimit使用的缓存后端
RATELIMIT_STORAGE = 'django_ratelimit.backends.cache.CacheBackend'

内容的提问来源于stack exchange,提问作者redtomato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:27:47