aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/topics/release-notes.md5
-rw-r--r--rest_framework/__init__.py2
-rw-r--r--rest_framework/permissions.py5
-rw-r--r--rest_framework/routers.py17
-rw-r--r--rest_framework/serializers.py8
-rw-r--r--rest_framework/tests/serializer.py18
6 files changed, 45 insertions, 10 deletions
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index 5777b82d..e7d62721 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -40,12 +40,15 @@ You can determine your currently installed version using `pip freeze`:
## 2.3.x series
-### Master
+### 2.3.2
+
+**Date**: 16th May 2013
* Added SearchFilter
* Added OrderingFilter
* Added GenericViewSet
* Bugfix: Multiple `@action` and `@link` methods now allowed on viewsets.
+* Bugfix: Fix API Root view issue with DjangoModelPermissions
### 2.3.2
diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py
index b4961e2f..0b1e67fb 100644
--- a/rest_framework/__init__.py
+++ b/rest_framework/__init__.py
@@ -1,4 +1,4 @@
-__version__ = '2.3.2'
+__version__ = '2.3.3'
VERSION = __version__ # synonym
diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py
index 751f31a7..45fcfd66 100644
--- a/rest_framework/permissions.py
+++ b/rest_framework/permissions.py
@@ -126,6 +126,11 @@ class DjangoModelPermissions(BasePermission):
if model_cls is None and queryset is not None:
model_cls = queryset.model
+ # Workaround to ensure DjangoModelPermissions are not applied
+ # to the root view when using DefaultRouter.
+ if model_cls is None and getattr(view, '_ignore_model_permissions'):
+ return True
+
assert model_cls, ('Cannot apply DjangoModelPermissions on a view that'
' does not have `.model` or `.queryset` property.')
diff --git a/rest_framework/routers.py b/rest_framework/routers.py
index 76714fd0..dba104c3 100644
--- a/rest_framework/routers.py
+++ b/rest_framework/routers.py
@@ -16,6 +16,7 @@ For example, you might have a `urls.py` that looks something like this:
from __future__ import unicode_literals
from collections import namedtuple
+from rest_framework import views
from rest_framework.compat import patterns, url
from rest_framework.decorators import api_view
from rest_framework.response import Response
@@ -217,14 +218,16 @@ class DefaultRouter(SimpleRouter):
for prefix, viewset, basename in self.registry:
api_root_dict[prefix] = list_name.format(basename=basename)
- @api_view(('GET',))
- def api_root(request, format=None):
- ret = {}
- for key, url_name in api_root_dict.items():
- ret[key] = reverse(url_name, request=request, format=format)
- return Response(ret)
+ class APIRoot(views.APIView):
+ _ignore_model_permissions = True
- return api_root
+ def get(self, request, format=None):
+ ret = {}
+ for key, url_name in api_root_dict.items():
+ ret[key] = reverse(url_name, request=request, format=format)
+ return Response(ret)
+
+ return APIRoot.as_view()
def get_urls(self):
"""
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index ecff2c52..7707de7a 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -649,8 +649,14 @@ class ModelSerializer(Serializer):
# Add the `read_only` flag to any fields that have bee specified
# in the `read_only_fields` option
for field_name in self.opts.read_only_fields:
+ assert field_name not in self.base_fields.keys(), \
+ "field '%s' on serializer '%s' specfied in " \
+ "`read_only_fields`, but also added " \
+ "as an explict field. Remove it from `read_only_fields`." % \
+ (field_name, self.__class__.__name__)
assert field_name in ret, \
- "read_only_fields on '%s' included invalid item '%s'" % \
+ "Noexistant field '%s' specified in `read_only_fields` " \
+ "on serializer '%s'." % \
(self.__class__.__name__, field_name)
ret[field_name].read_only = True
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
index 84e1ee4e..db3881f9 100644
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -78,6 +78,18 @@ class PersonSerializer(serializers.ModelSerializer):
read_only_fields = ('age',)
+class PersonSerializerInvalidReadOnly(serializers.ModelSerializer):
+ """
+ Testing for #652.
+ """
+ info = serializers.Field(source='info')
+
+ class Meta:
+ model = Person
+ fields = ('name', 'age', 'info')
+ read_only_fields = ('age', 'info')
+
+
class AlbumsSerializer(serializers.ModelSerializer):
class Meta:
@@ -189,6 +201,12 @@ class BasicTests(TestCase):
# Assert age is unchanged (35)
self.assertEqual(instance.age, self.person_data['age'])
+ def test_invalid_read_only_fields(self):
+ """
+ Regression test for #652.
+ """
+ self.assertRaises(AssertionError, PersonSerializerInvalidReadOnly, [])
+
class DictStyleSerializer(serializers.Serializer):
"""