Loading django/views/generic/base.py +10 −2 Original line number Diff line number Diff line Loading @@ -79,14 +79,22 @@ class View(object): return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs): allowed_methods = [m for m in self.http_method_names if hasattr(self, m)] logger.warning('Method Not Allowed (%s): %s', request.method, request.path, extra={ 'status_code': 405, 'request': self.request } ) return http.HttpResponseNotAllowed(allowed_methods) return http.HttpResponseNotAllowed(self._allowed_methods()) def options(self, request, *args, **kwargs): response = http.HttpResponse() response['Allow'] = ', '.join(self._allowed_methods()) response['Content-Length'] = 0 return response def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)] class TemplateResponseMixin(object): Loading tests/regressiontests/generic_views/base.py +52 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,58 @@ class ViewTest(unittest.TestCase): """ self.assertTrue(DecoratedDispatchView.as_view().is_decorated) def test_head_no_get(self): """ Test that a view class with no get responds to a HEAD request with HTTP 405. """ request = self.rf.head('/') view = PostOnlyView.as_view() self.assertEqual(405, view(request).status_code) def test_options(self): """ Test that views respond to HTTP OPTIONS requests with an Allow header appropriate for the methods implemented by the view class. """ request = self.rf.options('/') view = SimpleView.as_view() response = view(request) self.assertEqual(200, response.status_code) self.assertTrue(response['Allow']) def test_options_for_get_view(self): """ Test that a view implementing GET allows GET and HEAD. """ request = self.rf.options('/') view = SimpleView.as_view() response = view(request) self._assert_allows(response, 'GET', 'HEAD') def test_options_for_get_and_post_view(self): """ Test that a view implementing GET and POST allows GET, HEAD, and POST. """ request = self.rf.options('/') view = SimplePostView.as_view() response = view(request) self._assert_allows(response, 'GET', 'HEAD', 'POST') def test_options_for_post_view(self): """ Test that a view implementing POST allows POST. """ request = self.rf.options('/') view = PostOnlyView.as_view() response = view(request) self._assert_allows(response, 'POST') def _assert_allows(self, response, *expected_methods): "Assert allowed HTTP methods reported in the Allow response header" response_allows = set(response['Allow'].split(', ')) self.assertEqual(set(expected_methods + ('OPTIONS',)), response_allows) class TemplateViewTest(TestCase): urls = 'regressiontests.generic_views.urls' Loading Loading
django/views/generic/base.py +10 −2 Original line number Diff line number Diff line Loading @@ -79,14 +79,22 @@ class View(object): return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs): allowed_methods = [m for m in self.http_method_names if hasattr(self, m)] logger.warning('Method Not Allowed (%s): %s', request.method, request.path, extra={ 'status_code': 405, 'request': self.request } ) return http.HttpResponseNotAllowed(allowed_methods) return http.HttpResponseNotAllowed(self._allowed_methods()) def options(self, request, *args, **kwargs): response = http.HttpResponse() response['Allow'] = ', '.join(self._allowed_methods()) response['Content-Length'] = 0 return response def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)] class TemplateResponseMixin(object): Loading
tests/regressiontests/generic_views/base.py +52 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,58 @@ class ViewTest(unittest.TestCase): """ self.assertTrue(DecoratedDispatchView.as_view().is_decorated) def test_head_no_get(self): """ Test that a view class with no get responds to a HEAD request with HTTP 405. """ request = self.rf.head('/') view = PostOnlyView.as_view() self.assertEqual(405, view(request).status_code) def test_options(self): """ Test that views respond to HTTP OPTIONS requests with an Allow header appropriate for the methods implemented by the view class. """ request = self.rf.options('/') view = SimpleView.as_view() response = view(request) self.assertEqual(200, response.status_code) self.assertTrue(response['Allow']) def test_options_for_get_view(self): """ Test that a view implementing GET allows GET and HEAD. """ request = self.rf.options('/') view = SimpleView.as_view() response = view(request) self._assert_allows(response, 'GET', 'HEAD') def test_options_for_get_and_post_view(self): """ Test that a view implementing GET and POST allows GET, HEAD, and POST. """ request = self.rf.options('/') view = SimplePostView.as_view() response = view(request) self._assert_allows(response, 'GET', 'HEAD', 'POST') def test_options_for_post_view(self): """ Test that a view implementing POST allows POST. """ request = self.rf.options('/') view = PostOnlyView.as_view() response = view(request) self._assert_allows(response, 'POST') def _assert_allows(self, response, *expected_methods): "Assert allowed HTTP methods reported in the Allow response header" response_allows = set(response['Allow'].split(', ')) self.assertEqual(set(expected_methods + ('OPTIONS',)), response_allows) class TemplateViewTest(TestCase): urls = 'regressiontests.generic_views.urls' Loading