Fixed #15637 -- Added a require_safe decorator for views to accept GET or HEAD. Thanks, aaugustin and Julien.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16115 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-04-28 13:04:16 +00:00
parent 013ce8aca2
commit 086ab44336
3 changed files with 65 additions and 24 deletions

View File

@ -48,6 +48,9 @@ require_GET.__doc__ = "Decorator to require that a view only accept the GET meth
require_POST = require_http_methods(["POST"])
require_POST.__doc__ = "Decorator to require that a view only accept the POST method."
require_safe = require_http_methods(["GET", "HEAD"])
require_safe.__doc__ = "Decorator to require that a view only accept safe methods: GET and HEAD."
def condition(etag_func=None, last_modified_func=None):
"""
Decorator to support conditional retrieval (or change) for a view

View File

@ -10,31 +10,47 @@ various HTTP features.
Allowed HTTP methods
====================
The following decorators in :mod:`django.views.decorators.http` can be used to
restrict access to views based on the request method.
The decorators in :mod:`django.views.decorators.http` can be used to restrict
access to views based on the request method.
.. function:: require_http_methods(request_method_list)
This decorator is used to ensure that a view only accepts particular request
methods. Usage::
Decorator to require that a view only accept particular request
methods. Usage::
from django.views.decorators.http import require_http_methods
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
pass
@require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
pass
Note that request methods should be in uppercase.
Note that request methods should be in uppercase.
.. function:: require_GET()
Decorator to require that a view only accept the GET method.
Decorator to require that a view only accept the GET method.
.. function:: require_POST()
Decorator to require that a view only accept the POST method.
Decorator to require that a view only accept the POST method.
.. function:: require_safe()
.. versionadded:: 1.4
Decorator to require that a view only accept the GET and HEAD methods.
These methods are commonly considered "safe" because they should not have
the significance of taking an action other than retrieving the requested
resource.
.. note::
Django will automatically strip the content of responses to HEAD
requests while leaving the headers unchanged, so you may handle HEAD
requests exactly like GET requests in your views. Since some software,
such as link checkers, rely on HEAD requests, you might prefer
using ``require_safe`` instead of ``require_GET``.
Conditional view processing
===========================
@ -48,9 +64,9 @@ control caching behavior on particular views.
.. function:: last_modified(last_modified_func)
These decorators can be used to generate ``ETag`` and ``Last-Modified``
headers; see
:doc:`conditional view processing </topics/conditional-view-processing>`.
These decorators can be used to generate ``ETag`` and ``Last-Modified``
headers; see
:doc:`conditional view processing </topics/conditional-view-processing>`.
.. module:: django.views.decorators.gzip
@ -62,9 +78,9 @@ compression on a per-view basis.
.. function:: gzip_page()
This decorator compresses content if the browser allows gzip compression.
It sets the ``Vary`` header accordingly, so that caches will base their
storage on the ``Accept-Encoding`` header.
This decorator compresses content if the browser allows gzip compression.
It sets the ``Vary`` header accordingly, so that caches will base their
storage on the ``Accept-Encoding`` header.
.. module:: django.views.decorators.vary
@ -78,7 +94,7 @@ caching based on specific request headers.
.. function:: vary_on_headers(*headers)
The ``Vary`` header defines which request headers a cache mechanism should take
into account when building its cache key.
The ``Vary`` header defines which request headers a cache mechanism should take
into account when building its cache key.
See :ref:`using vary headers <using-vary-headers>`.
See :ref:`using vary headers <using-vary-headers>`.

View File

@ -2,11 +2,11 @@ from functools import wraps
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.contrib.admin.views.decorators import staff_member_required
from django.http import HttpResponse, HttpRequest
from django.http import HttpResponse, HttpRequest, HttpResponseNotAllowed
from django.utils.decorators import method_decorator
from django.utils.functional import allow_lazy, lazy, memoize
from django.utils.unittest import TestCase
from django.views.decorators.http import require_http_methods, require_GET, require_POST
from django.views.decorators.http import require_http_methods, require_GET, require_POST, require_safe
from django.views.decorators.vary import vary_on_headers, vary_on_cookie
from django.views.decorators.cache import cache_page, never_cache, cache_control
@ -20,6 +20,7 @@ fully_decorated.anything = "Expected __dict__"
fully_decorated = require_http_methods(["GET"])(fully_decorated)
fully_decorated = require_GET(fully_decorated)
fully_decorated = require_POST(fully_decorated)
fully_decorated = require_safe(fully_decorated)
# django.views.decorators.vary
fully_decorated = vary_on_headers('Accept-language')(fully_decorated)
@ -111,6 +112,27 @@ class DecoratorsTest(TestCase):
my_view_cached4 = cache_page()(my_view)
self.assertEqual(my_view_cached4(HttpRequest()), "response")
def test_require_safe_accepts_only_safe_methods(self):
"""
Test for the require_safe decorator.
A view returns either a response or an exception.
Refs #15637.
"""
def my_view(request):
return HttpResponse("OK")
my_safe_view = require_safe(my_view)
request = HttpRequest()
request.method = 'GET'
self.assertTrue(isinstance(my_safe_view(request), HttpResponse))
request.method = 'HEAD'
self.assertTrue(isinstance(my_safe_view(request), HttpResponse))
request.method = 'POST'
self.assertTrue(isinstance(my_safe_view(request), HttpResponseNotAllowed))
request.method = 'PUT'
self.assertTrue(isinstance(my_safe_view(request), HttpResponseNotAllowed))
request.method = 'DELETE'
self.assertTrue(isinstance(my_safe_view(request), HttpResponseNotAllowed))
# For testing method_decorator, a decorator that assumes a single argument.
# We will get type arguments if there is a mismatch in the number of arguments.