Django URL 验证
嗨,
我想检查一下我的网址,看看它们是用POST还是GET请求,并且要确保数据是正确的。所以我想在这些网址调用相应的视图之前先验证一下它们。我打算在视图和网址之间写一些中间件,这样可以保护系统的安全。我不太清楚怎么把数据通过中间件传递到视图。在中间件里,我会写单元测试代码,来验证网址是否有效,如果有效就传给相应的视图,如果无效就返回404错误。请问有没有人能建议我该怎么处理这个问题?或者有没有其他更好的方法来进行这个验证。
谢谢大家。
2 个回答
就像其他人说的,你必须在你的视图中处理这个问题,或者你可以先说说你想要实现什么,这样能更好地帮助你...
总之,你不能在 process_request 里创建一个响应对象,你只能在相关的请求上添加变量或者修改变量,比如 Django 使用的 sessionid 变量,或者更新任何已有的请求变量...
所以,你必须使用 process_view,这个函数在 process_request 之后被触发,并且在你的视图函数执行之前。因为你手上有请求对象,你可以通过 request.GET 或 request.POST 来检查 GET 或 POST 数据。
为了做到这一点,你需要在 settings.py 中把你的中间件类添加到 MIDDLEWARE_CLASSES,并写一个合适的中间件 process_view 函数。关于如何写中间件,可以查看 中间件文档,也可以看看 Django 里已有的中间件。或者告诉我你想要实现什么...
你应该在视图中检查请求类型,而不是在中间件里。正如我在上面的评论中提到的,仅仅通过 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 的文档。