aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/exceptions.py33
-rw-r--r--rest_framework/relations.py15
-rw-r--r--rest_framework/request.py2
-rw-r--r--rest_framework/tests/test_relations.py20
4 files changed, 39 insertions, 31 deletions
diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py
index 425a7214..4276625a 100644
--- a/rest_framework/exceptions.py
+++ b/rest_framework/exceptions.py
@@ -6,6 +6,7 @@ In addition Django's built in 403 and 404 exceptions are handled.
"""
from __future__ import unicode_literals
from rest_framework import status
+import math
class APIException(Exception):
@@ -13,40 +14,32 @@ class APIException(Exception):
Base class for REST framework exceptions.
Subclasses should provide `.status_code` and `.detail` properties.
"""
- pass
+ status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
+ default_detail = ''
+
+ def __init__(self, detail=None):
+ self.detail = detail or self.default_detail
class ParseError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = 'Malformed request.'
- def __init__(self, detail=None):
- self.detail = detail or self.default_detail
-
class AuthenticationFailed(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = 'Incorrect authentication credentials.'
- def __init__(self, detail=None):
- self.detail = detail or self.default_detail
-
class NotAuthenticated(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = 'Authentication credentials were not provided.'
- def __init__(self, detail=None):
- self.detail = detail or self.default_detail
-
class PermissionDenied(APIException):
status_code = status.HTTP_403_FORBIDDEN
default_detail = 'You do not have permission to perform this action.'
- def __init__(self, detail=None):
- self.detail = detail or self.default_detail
-
class MethodNotAllowed(APIException):
status_code = status.HTTP_405_METHOD_NOT_ALLOWED
@@ -75,14 +68,14 @@ class UnsupportedMediaType(APIException):
class Throttled(APIException):
status_code = status.HTTP_429_TOO_MANY_REQUESTS
- default_detail = "Request was throttled."
+ default_detail = 'Request was throttled.'
extra_detail = "Expected available in %d second%s."
def __init__(self, wait=None, detail=None):
- import math
- self.wait = wait and math.ceil(wait) or None
- if wait is not None:
- format = detail or self.default_detail + self.extra_detail
- self.detail = format % (self.wait, self.wait != 1 and 's' or '')
- else:
+ if wait is None:
self.detail = detail or self.default_detail
+ self.wait = None
+ else:
+ format = (detail or self.default_detail) + self.extra_detail
+ self.detail = format % (wait, wait != 1 and 's' or '')
+ self.wait = math.ceil(wait)
diff --git a/rest_framework/relations.py b/rest_framework/relations.py
index 35c00bf1..02185c2f 100644
--- a/rest_framework/relations.py
+++ b/rest_framework/relations.py
@@ -65,16 +65,11 @@ class RelatedField(WritableField):
def initialize(self, parent, field_name):
super(RelatedField, self).initialize(parent, field_name)
if self.queryset is None and not self.read_only:
- try:
- manager = getattr(self.parent.opts.model, self.source or field_name)
- if hasattr(manager, 'related'): # Forward
- self.queryset = manager.related.model._default_manager.all()
- else: # Reverse
- self.queryset = manager.field.rel.to._default_manager.all()
- except Exception:
- msg = ('Serializer related fields must include a `queryset`' +
- ' argument or set `read_only=True')
- raise Exception(msg)
+ manager = getattr(self.parent.opts.model, self.source or field_name)
+ if hasattr(manager, 'related'): # Forward
+ self.queryset = manager.related.model._default_manager.all()
+ else: # Reverse
+ self.queryset = manager.field.rel.to._default_manager.all()
### We need this stuff to make form choices work...
diff --git a/rest_framework/request.py b/rest_framework/request.py
index fcea2508..d1f04ec5 100644
--- a/rest_framework/request.py
+++ b/rest_framework/request.py
@@ -223,7 +223,7 @@ class Request(object):
def user(self, value):
"""
Sets the user on the current request. This is necessary to maintain
- compatilbility with django.contrib.auth where the user proprety is
+ compatibility with django.contrib.auth where the user property is
set in the login and logout functions.
"""
self._user = value
diff --git a/rest_framework/tests/test_relations.py b/rest_framework/tests/test_relations.py
index d19219c9..f52e0e1e 100644
--- a/rest_framework/tests/test_relations.py
+++ b/rest_framework/tests/test_relations.py
@@ -98,3 +98,23 @@ class RelatedFieldSourceTests(TestCase):
obj = ClassWithQuerysetMethod()
value = field.field_to_native(obj, 'field_name')
self.assertEqual(value, ['BlogPost object'])
+
+ # Regression for #1129
+ def test_exception_for_incorect_fk(self):
+ """
+ Check that the exception message are correct if the source field
+ doesn't exist.
+ """
+ from rest_framework.tests.models import ManyToManySource
+ class Meta:
+ model = ManyToManySource
+ attrs = {
+ 'name': serializers.SlugRelatedField(
+ slug_field='name', source='banzai'),
+ 'Meta': Meta,
+ }
+
+ TestSerializer = type(str('TestSerializer'),
+ (serializers.ModelSerializer,), attrs)
+ with self.assertRaises(AttributeError):
+ TestSerializer(data={'name': 'foo'})