Django URL 验证

3 投票
2 回答
3640 浏览
提问于 2025-04-16 18:54

嗨,

我想检查一下我的网址,看看它们是用POST还是GET请求,并且要确保数据是正确的。所以我想在这些网址调用相应的视图之前先验证一下它们。我打算在视图和网址之间写一些中间件,这样可以保护系统的安全。我不太清楚怎么把数据通过中间件传递到视图。在中间件里,我会写单元测试代码,来验证网址是否有效,如果有效就传给相应的视图,如果无效就返回404错误。请问有没有人能建议我该怎么处理这个问题?或者有没有其他更好的方法来进行这个验证。

谢谢大家。

2 个回答

2

就像其他人说的,你必须在你的视图中处理这个问题,或者你可以先说说你想要实现什么,这样能更好地帮助你...

总之,你不能在 process_request 里创建一个响应对象,你只能在相关的请求上添加变量或者修改变量,比如 Django 使用的 sessionid 变量,或者更新任何已有的请求变量...

所以,你必须使用 process_view,这个函数在 process_request 之后被触发,并且在你的视图函数执行之前。因为你手上有请求对象,你可以通过 request.GETrequest.POST 来检查 GET 或 POST 数据。

为了做到这一点,你需要在 settings.py 中把你的中间件类添加到 MIDDLEWARE_CLASSES,并写一个合适的中间件 process_view 函数。关于如何写中间件,可以查看 中间件文档,也可以看看 Django 里已有的中间件。或者告诉我你想要实现什么...

5

你应该在视图中检查请求类型,而不是在中间件里。正如我在上面的评论中提到的,仅仅通过 URL 是无法判断请求是否为 POST 的,更别提判断它携带了什么 POST 数据了。

在视图中检查请求类型其实很简单,只需要检查 request.method 是否等于 "GET""POST" 就可以了。

如果你经常需要这样做,可以创建一个装饰器来帮你完成这个检查。比如,下面这个装饰器会检查调用这个视图时是否使用了 GET 请求,如果不是,就会返回一个 HttpResponseBadRequest 对象(状态码 400):

# untested code, use with care
def require_GET(view_func):
    def wrap(request, *args, **kwargs):
        if request.method != "GET":
            return HttpResponseBadRequest("Expecting GET request")
        return view_func(request, *args, **kwargs)
    wrap.__doc__ = view_func.__doc__
    wrap.__dict__ = view_func.__dict__
    wrap.__name__ = view_func.__name__
    return wrap

然后你只需要在你的视图函数前面加上 @require_GET,这样每次调用这个视图时都会自动进行检查。例如:

@require_GET
def your_view(request):
    # ...

对于 POST 请求,你也可以做同样的事情。

这里有一个示例装饰器,它会检查 POST 请求,并可以接受一个可选的字段列表,这些字段必须在 POST 请求中提供。

# again, untested so use with care.
def require_POST(view_func, required_fields=None):
    def wrap(request, *args, **kwargs):
        if request.method != "POST":
            return HttpResponseBadRequest("Expecting POST request")
        if required_fields:
            for f in required_fields:
                if f not in request.POST:
                    return HttpResponseBadRequest("Expecting field %s" % f)
        return view_func(request, *args, **kwargs)
    wrap.__doc__ = view_func.__doc__
    wrap.__dict__ = view_func.__dict__
    wrap.__name__ = view_func.__name__
    return wrap

使用方法如下:

@require_POST
def another_view(request):
    # ...

或者:

@require_POST(required_fields=("username", "password"))
def custom_login_view(request):
    # ...

更新

好吧,我错了。我其实是在重复造轮子。

Django 已经提供了 @require_GET@require_POST 这两个装饰器。你可以查看 django.views.decorators.http 的文档。

撰写回答