aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/generics.py17
-rw-r--r--rest_framework/request.py4
-rw-r--r--rest_framework/response.py2
-rw-r--r--rest_framework/templates/rest_framework/base.html2
-rw-r--r--rest_framework/templates/rest_framework/login_base.html15
-rw-r--r--rest_framework/test.py4
-rw-r--r--rest_framework/tests/test_fields.py18
-rw-r--r--rest_framework/tests/test_testing.py11
-rw-r--r--rest_framework/urls.py8
9 files changed, 61 insertions, 20 deletions
diff --git a/rest_framework/generics.py b/rest_framework/generics.py
index 7fc9db36..aea636f1 100644
--- a/rest_framework/generics.py
+++ b/rest_framework/generics.py
@@ -43,6 +43,10 @@ class GenericAPIView(views.APIView):
# You'll need to either set these attributes,
# or override `get_queryset()`/`get_serializer_class()`.
+ # If you are overriding a view method, it is important that you call
+ # `get_queryset()` instead of accessing the `queryset` property directly,
+ # as `queryset` will get evaluated only once, and those results are cached
+ # for all subsequent requests.
queryset = None
serializer_class = None
@@ -185,7 +189,13 @@ class GenericAPIView(views.APIView):
"""
Returns the list of filter backends that this view requires.
"""
- filter_backends = self.filter_backends or []
+ if self.filter_backends is None:
+ filter_backends = []
+ else:
+ # Note that we are returning a *copy* of the class attribute,
+ # so that it is safe for the view to mutate it if needed.
+ filter_backends = list(self.filter_backends)
+
if not filter_backends and self.filter_backend:
warnings.warn(
'The `filter_backend` attribute and `FILTER_BACKEND` setting '
@@ -195,6 +205,7 @@ class GenericAPIView(views.APIView):
PendingDeprecationWarning, stacklevel=2
)
filter_backends = [self.filter_backend]
+
return filter_backends
@@ -258,6 +269,10 @@ class GenericAPIView(views.APIView):
This must be an iterable, and may be a queryset.
Defaults to using `self.queryset`.
+ This method should always be used rather than accessing `self.queryset`
+ directly, as `self.queryset` gets evaluated only once, and those results
+ are cached for all subsequent requests.
+
You may want to override this if you need to provide different
querysets depending on the incoming request.
diff --git a/rest_framework/request.py b/rest_framework/request.py
index 735a9288..4f9345f3 100644
--- a/rest_framework/request.py
+++ b/rest_framework/request.py
@@ -284,8 +284,8 @@ class Request(object):
self._method = self._request.method
# Allow X-HTTP-METHOD-OVERRIDE header
- self._method = self.META.get('HTTP_X_HTTP_METHOD_OVERRIDE',
- self._method)
+ if 'HTTP_X_HTTP_METHOD_OVERRIDE' in self.META:
+ self._method = self.META['HTTP_X_HTTP_METHOD_OVERRIDE'].upper()
def _load_stream(self):
"""
diff --git a/rest_framework/response.py b/rest_framework/response.py
index 5c02ea50..25b78524 100644
--- a/rest_framework/response.py
+++ b/rest_framework/response.py
@@ -20,7 +20,7 @@ class Response(SimpleTemplateResponse):
if django.VERSION >= (1, 4):
rendering_attrs = SimpleTemplateResponse.rendering_attrs + ['_closable_objects']
- def __init__(self, data=None, status=200,
+ def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
"""
diff --git a/rest_framework/templates/rest_framework/base.html b/rest_framework/templates/rest_framework/base.html
index e96fa8ec..ee96b6ee 100644
--- a/rest_framework/templates/rest_framework/base.html
+++ b/rest_framework/templates/rest_framework/base.html
@@ -24,6 +24,7 @@
{% endblock %}
</head>
+ {% block body %}
<body class="{% block bodyclass %}{% endblock %} container">
<div class="wrapper">
@@ -230,4 +231,5 @@
<script src="{% static "rest_framework/js/default.js" %}"></script>
{% endblock %}
</body>
+ {% endblock %}
</html>
diff --git a/rest_framework/templates/rest_framework/login_base.html b/rest_framework/templates/rest_framework/login_base.html
index be9a0072..312a1138 100644
--- a/rest_framework/templates/rest_framework/login_base.html
+++ b/rest_framework/templates/rest_framework/login_base.html
@@ -1,17 +1,8 @@
+{% extends "rest_framework/base.html" %}
{% load url from future %}
{% load rest_framework %}
-<html>
-
- <head>
- {% block style %}
- {% block bootstrap_theme %}
- <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/>
- <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/>
- {% endblock %}
- <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/>
- {% endblock %}
- </head>
+ {% block body %}
<body class="container">
<div class="container-fluid" style="margin-top: 30px">
@@ -50,4 +41,4 @@
</div><!-- /.row-fluid -->
</div><!-- /.container-fluid -->
</body>
-</html>
+ {% endblock %}
diff --git a/rest_framework/test.py b/rest_framework/test.py
index 284bcee0..d4ec50a0 100644
--- a/rest_framework/test.py
+++ b/rest_framework/test.py
@@ -154,6 +154,10 @@ class APIClient(APIRequestFactory, DjangoClient):
kwargs.update(self._credentials)
return super(APIClient, self).request(**kwargs)
+ def logout(self):
+ self._credentials = {}
+ return super(APIClient, self).logout()
+
class APITransactionTestCase(testcases.TransactionTestCase):
client_class = APIClient
diff --git a/rest_framework/tests/test_fields.py b/rest_framework/tests/test_fields.py
index b04b947f..17d12f23 100644
--- a/rest_framework/tests/test_fields.py
+++ b/rest_framework/tests/test_fields.py
@@ -1002,3 +1002,21 @@ class BooleanField(TestCase):
bool_field = serializers.BooleanField(required=True)
self.assertFalse(BooleanRequiredSerializer(data={}).is_valid())
+
+
+class SerializerMethodFieldTest(TestCase):
+ """
+ Tests for the SerializerMethodField field_to_native() behavior
+ """
+ class SerializerTest(serializers.Serializer):
+ def get_my_test(self, obj):
+ return obj.my_test[0:5]
+
+ class Example():
+ my_test = 'Hey, this is a test !'
+
+ def test_field_to_native(self):
+ s = serializers.SerializerMethodField('get_my_test')
+ s.initialize(self.SerializerTest(), 'name')
+ result = s.field_to_native(self.Example(), None)
+ self.assertEqual(result, 'Hey, ')
diff --git a/rest_framework/tests/test_testing.py b/rest_framework/tests/test_testing.py
index a55d4b22..b16d1962 100644
--- a/rest_framework/tests/test_testing.py
+++ b/rest_framework/tests/test_testing.py
@@ -99,6 +99,17 @@ class TestAPITestClient(TestCase):
self.assertEqual(response.status_code, 403)
self.assertEqual(response.data, expected)
+ def test_can_logout(self):
+ """
+ `logout()` reset stored credentials
+ """
+ self.client.credentials(HTTP_AUTHORIZATION='example')
+ response = self.client.get('/view/')
+ self.assertEqual(response.data['auth'], 'example')
+ self.client.logout()
+ response = self.client.get('/view/')
+ self.assertEqual(response.data['auth'], b'')
+
class TestAPIRequestFactory(TestCase):
def test_csrf_exempt_by_default(self):
diff --git a/rest_framework/urls.py b/rest_framework/urls.py
index 9c4719f1..5d70f899 100644
--- a/rest_framework/urls.py
+++ b/rest_framework/urls.py
@@ -2,15 +2,15 @@
Login and logout views for the browsable API.
Add these to your root URLconf if you're using the browsable API and
-your API requires authentication.
-
-The urls must be namespaced as 'rest_framework', and you should make sure
-your authentication settings include `SessionAuthentication`.
+your API requires authentication:
urlpatterns = patterns('',
...
url(r'^auth', include('rest_framework.urls', namespace='rest_framework'))
)
+
+The urls must be namespaced as 'rest_framework', and you should make sure
+your authentication settings include `SessionAuthentication`.
"""
from __future__ import unicode_literals
from rest_framework.compat import patterns, url