From 8f1d42e7d5146e19842d2837259284f8730b451d Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Mon, 2 Feb 2015 10:50:54 +0200 Subject: [PATCH 1/8] Fixed typos in docstrings. --- rest_framework/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 42d1e3700..2fd907ecd 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -633,11 +633,11 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data): If we don't do this explicitly they'd get a less helpful error when calling `.save()` on the serializer. - We don't *automatically* support these sorts of nested writes brecause + We don't *automatically* support these sorts of nested writes because there are too many ambiguities to define a default behavior. Eg. Suppose we have a `UserSerializer` with a nested profile. How should - we handle the case of an update, where the `profile` realtionship does + we handle the case of an update, where the `profile` relationship does not exist? Any of the following might be valid: * Raise an application error. From 4b65e9e42be068ad3e742692262451f8836f09d3 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Mon, 2 Feb 2015 16:14:34 -0800 Subject: [PATCH 2/8] Fixed missing whitespace in error string. --- rest_framework/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 2fd907ecd..d76658b03 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -177,7 +177,7 @@ class BaseSerializer(Field): ) assert hasattr(self, 'initial_data'), ( - 'Cannot call `.is_valid()` as no `data=` keyword argument was' + 'Cannot call `.is_valid()` as no `data=` keyword argument was ' 'passed when instantiating the serializer instance.' ) From f6765696610a0de3cf7d9986a2dfab40ca37e88b Mon Sep 17 00:00:00 2001 From: James Cooke Date: Tue, 3 Feb 2015 13:43:03 +0000 Subject: [PATCH 3/8] Small documentation fixes * Remove "you you" from viewsets API-guide * Fix link from routers API-guide to viewsets API-guide --- docs/api-guide/routers.md | 2 +- docs/api-guide/viewsets.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 592f7d66f..222b6cd25 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -304,7 +304,7 @@ The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (an The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions-routers] for creating [nested viewsets][drf-extensions-nested-viewsets], [collection level controllers][drf-extensions-collection-level-controllers] with [customizable endpoint names][drf-extensions-customizable-endpoint-names]. [cite]: http://guides.rubyonrails.org/routing.html -[route-decorators]: viewsets.html#marking-extra-actions-for-routing +[route-decorators]: viewsets.md#marking-extra-actions-for-routing [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers [wq.db]: http://wq.io/wq.db [wq.db-router]: http://wq.io/docs/app.py diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index b09dfc9e9..bbf92c6ce 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -201,7 +201,7 @@ Note that you can use any of the standard attributes or method overrides provide def get_queryset(self): return self.request.user.accounts.all() -Note however that upon removal of the `queryset` property from your `ViewSet`, any associated [router][routers] will be unable to derive the base_name of your Model automatically, and so you you will have to specify the `base_name` kwarg as part of your [router registration][routers]. +Note however that upon removal of the `queryset` property from your `ViewSet`, any associated [router][routers] will be unable to derive the base_name of your Model automatically, and so you will have to specify the `base_name` kwarg as part of your [router registration][routers]. Also note that although this class provides the complete set of create/list/retrieve/update/destroy actions by default, you can restrict the available operations by using the standard permission classes. From 76efbdddb69d0e7279c1b9de066e829f34019609 Mon Sep 17 00:00:00 2001 From: Warren Jin Date: Tue, 3 Feb 2015 17:18:54 -0500 Subject: [PATCH 4/8] docs --- docs/api-guide/fields.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index b3d274ddb..f379ac720 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -567,6 +567,10 @@ The [drf-compound-fields][drf-compound-fields] package provides "compound" seria The [drf-extra-fields][drf-extra-fields] package provides extra serializer fields for REST framework, including `Base64ImageField` and `PointField` classes. +## djangrestframework-recursive + +the [djangorestframework-recursive][djangorestframework-recursive] package provides a `RecursiveField` for serializing and deserializing recursive structures + ## django-rest-framework-gis The [django-rest-framework-gis][django-rest-framework-gis] package provides geographic addons for django rest framework like a `GeometryField` field and a GeoJSON serializer. @@ -583,6 +587,7 @@ The [django-rest-framework-hstore][django-rest-framework-hstore] package provide [iso8601]: http://www.w3.org/TR/NOTE-datetime [drf-compound-fields]: http://drf-compound-fields.readthedocs.org [drf-extra-fields]: https://github.com/Hipo/drf-extra-fields +[djangorestframework-recursive]: https://github.com/heywbj/django-rest-framework-recursive [django-rest-framework-gis]: https://github.com/djangonauts/django-rest-framework-gis [django-rest-framework-hstore]: https://github.com/djangonauts/django-rest-framework-hstore [django-hstore]: https://github.com/djangonauts/django-hstore From 7bb5fd270da98d8957efb4bf0e4bd4679ddbcf5f Mon Sep 17 00:00:00 2001 From: Greg Kempe Date: Wed, 4 Feb 2015 16:03:03 +0200 Subject: [PATCH 5/8] FIX: Don't default to list in method args Fixes @list_route and @detail_route so that they don't initialize their `methods` parameter as a list. In some cases the list gets cleared, and the result is that default parameter is now empty, and may get reused unexpectedly. --- rest_framework/decorators.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index 325435b3f..a68227c14 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -109,10 +109,12 @@ def permission_classes(permission_classes): return decorator -def detail_route(methods=['get'], **kwargs): +def detail_route(methods=None, **kwargs): """ Used to mark a method on a ViewSet that should be routed for detail requests. """ + if methods is None: + methods = ['get'] def decorator(func): func.bind_to_methods = methods func.detail = True @@ -121,10 +123,12 @@ def detail_route(methods=['get'], **kwargs): return decorator -def list_route(methods=['get'], **kwargs): +def list_route(methods=None, **kwargs): """ Used to mark a method on a ViewSet that should be routed for list requests. """ + if methods is None: + methods = ['get'] def decorator(func): func.bind_to_methods = methods func.detail = False From 58e7bbc8ecad8016cc18f7dbd31b235cb515b785 Mon Sep 17 00:00:00 2001 From: Ofir Ovadia Date: Wed, 4 Feb 2015 16:08:41 +0200 Subject: [PATCH 6/8] Prefetching the user object when getting the token in TokenAuthentication. Since the user object is fetched 4 lines after getting Token from the database, this removes a DB query for each token-authenticated request. --- rest_framework/authentication.py | 2 +- tests/test_authentication.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index 4832ad33b..f7601fb12 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -167,7 +167,7 @@ class TokenAuthentication(BaseAuthentication): def authenticate_credentials(self, key): try: - token = self.model.objects.get(key=key) + token = self.model.objects.select_related('user').get(key=key) except self.model.DoesNotExist: raise exceptions.AuthenticationFailed('Invalid token') diff --git a/tests/test_authentication.py b/tests/test_authentication.py index 44837c4ef..caabcc214 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -202,6 +202,12 @@ class TokenAuthTests(TestCase): response = self.csrf_client.post('/token/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth) self.assertEqual(response.status_code, status.HTTP_200_OK) + def test_post_json_makes_one_db_query(self): + """Ensure that authenticating a user using a token performs only one DB query""" + auth = "Token " + self.key + func_to_test = lambda: self.csrf_client.post('/token/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth) + self.assertNumQueries(1, func_to_test) + def test_post_form_failing_token_auth(self): """Ensure POSTing form over token auth without correct credentials fails""" response = self.csrf_client.post('/token/', {'example': 'example'}) From d920683237bd2eb17d110a80fc09708a67340f01 Mon Sep 17 00:00:00 2001 From: Greg Kempe Date: Wed, 4 Feb 2015 16:13:30 +0200 Subject: [PATCH 7/8] Use inline if --- rest_framework/decorators.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index a68227c14..7604eae13 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -18,8 +18,7 @@ def api_view(http_method_names=None): Decorator that converts a function-based view into an APIView subclass. Takes a list of allowed methods for the view as an argument. """ - if http_method_names is None: - http_method_names = ['GET'] + http_method_names = ['GET'] if http_method_names is None else http_method_names def decorator(func): @@ -113,8 +112,8 @@ def detail_route(methods=None, **kwargs): """ Used to mark a method on a ViewSet that should be routed for detail requests. """ - if methods is None: - methods = ['get'] + methods = ['get'] if methods is None else methods + def decorator(func): func.bind_to_methods = methods func.detail = True @@ -127,8 +126,8 @@ def list_route(methods=None, **kwargs): """ Used to mark a method on a ViewSet that should be routed for list requests. """ - if methods is None: - methods = ['get'] + methods = ['get'] if methods is None else methods + def decorator(func): func.bind_to_methods = methods func.detail = False From e13d2af1374c8a2b2146e1126d9406bfb4bbd9ec Mon Sep 17 00:00:00 2001 From: Greg Kempe Date: Wed, 4 Feb 2015 16:26:23 +0200 Subject: [PATCH 8/8] Parens around if clause --- rest_framework/decorators.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index 7604eae13..21de1acf4 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -18,7 +18,7 @@ def api_view(http_method_names=None): Decorator that converts a function-based view into an APIView subclass. Takes a list of allowed methods for the view as an argument. """ - http_method_names = ['GET'] if http_method_names is None else http_method_names + http_method_names = ['GET'] if (http_method_names is None) else http_method_names def decorator(func): @@ -112,7 +112,7 @@ def detail_route(methods=None, **kwargs): """ Used to mark a method on a ViewSet that should be routed for detail requests. """ - methods = ['get'] if methods is None else methods + methods = ['get'] if (methods is None) else methods def decorator(func): func.bind_to_methods = methods @@ -126,7 +126,7 @@ def list_route(methods=None, **kwargs): """ Used to mark a method on a ViewSet that should be routed for list requests. """ - methods = ['get'] if methods is None else methods + methods = ['get'] if (methods is None) else methods def decorator(func): func.bind_to_methods = methods