diff options
| author | Tom Christie | 2013-01-04 13:50:40 +0000 | 
|---|---|---|
| committer | Tom Christie | 2013-01-04 13:50:40 +0000 | 
| commit | eb14278a3b08247c0aff5b2338a98203b51728c3 (patch) | |
| tree | a7ee5329f62b57d34c8e7de9f9bc73e35ec42896 /rest_framework/relations.py | |
| parent | 4c86fd46d772e1fd3789d9ed2a76b9b92cce0872 (diff) | |
| download | django-rest-framework-eb14278a3b08247c0aff5b2338a98203b51728c3.tar.bz2 | |
Add proper validation for updating relational fields with incorrect types.  Fixes #446.
Diffstat (limited to 'rest_framework/relations.py')
| -rw-r--r-- | rest_framework/relations.py | 48 | 
1 files changed, 37 insertions, 11 deletions
| diff --git a/rest_framework/relations.py b/rest_framework/relations.py index ae0d3de8..fcef42dd 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -276,6 +276,11 @@ class SlugRelatedField(RelatedField):      default_read_only = False      form_field_class = forms.ChoiceField +    default_error_messages = { +        'does_not_exist': _("Object with %s=%s does not exist."), +        'invalid': _('Invalid value.'), +    } +      def __init__(self, *args, **kwargs):          self.slug_field = kwargs.pop('slug_field', None)          assert self.slug_field, 'slug_field is required' @@ -291,8 +296,11 @@ class SlugRelatedField(RelatedField):          try:              return self.queryset.get(**{self.slug_field: data})          except ObjectDoesNotExist: -            raise ValidationError('Object with %s=%s does not exist.' % +            raise ValidationError(self.error_messages['does_not_exist'] %                                    (self.slug_field, unicode(data))) +        except (TypeError, ValueError): +            msg = self.error_messages['invalid'] +            raise ValidationError(msg)  class ManySlugRelatedField(ManyRelatedMixin, SlugRelatedField): @@ -311,6 +319,14 @@ class HyperlinkedRelatedField(RelatedField):      default_read_only = False      form_field_class = forms.ChoiceField +    default_error_messages = { +        'no_match': _('Invalid hyperlink - No URL match'), +        'incorrect_match': _('Invalid hyperlink - Incorrect URL match'), +        'configuration_error': _('Invalid hyperlink due to configuration error'), +        'does_not_exist': _("Invalid hyperlink - object does not exist."), +        'invalid': _('Invalid value.'), +    } +      def __init__(self, *args, **kwargs):          try:              self.view_name = kwargs.pop('view_name') @@ -347,7 +363,7 @@ class HyperlinkedRelatedField(RelatedField):          slug = getattr(obj, self.slug_field, None)          if not slug: -            raise ValidationError('Could not resolve URL for field using view name "%s"' % view_name) +            raise Exception('Could not resolve URL for field using view name "%s"' % view_name)          kwargs = {self.slug_url_kwarg: slug}          try: @@ -361,7 +377,7 @@ class HyperlinkedRelatedField(RelatedField):          except:              pass -        raise ValidationError('Could not resolve URL for field using view name "%s"' % view_name) +        raise Exception('Could not resolve URL for field using view name "%s"' % view_name)      def from_native(self, value):          # Convert URL -> model instance pk @@ -369,7 +385,13 @@ class HyperlinkedRelatedField(RelatedField):          if self.queryset is None:              raise Exception('Writable related fields must include a `queryset` argument') -        if value.startswith('http:') or value.startswith('https:'): +        try: +            http_prefix = value.startswith('http:') or value.startswith('https:') +        except AttributeError: +            msg = self.error_messages['invalid'] +            raise ValidationError(msg) + +        if http_prefix:              # If needed convert absolute URLs to relative path              value = urlparse(value).path              prefix = get_script_prefix() @@ -379,10 +401,10 @@ class HyperlinkedRelatedField(RelatedField):          try:              match = resolve(value)          except: -            raise ValidationError('Invalid hyperlink - No URL match') +            raise ValidationError(self.error_messages['no_match'])          if match.url_name != self.view_name: -            raise ValidationError('Invalid hyperlink - Incorrect URL match') +            raise ValidationError(self.error_messages['incorrect_match'])          pk = match.kwargs.get(self.pk_url_kwarg, None)          slug = match.kwargs.get(self.slug_url_kwarg, None) @@ -394,14 +416,18 @@ class HyperlinkedRelatedField(RelatedField):          elif slug is not None:              slug_field = self.get_slug_field()              queryset = self.queryset.filter(**{slug_field: slug}) -        # If none of those are defined, it's an error. +        # If none of those are defined, it's probably a configuation error.          else: -            raise ValidationError('Invalid hyperlink') +            raise ValidationError(self.error_messages['configuration_error'])          try:              obj = queryset.get()          except ObjectDoesNotExist: -            raise ValidationError('Invalid hyperlink - object does not exist.') +            raise ValidationError(self.error_messages['does_not_exist']) +        except (TypeError, ValueError): +            msg = self.error_messages['invalid'] +            raise ValidationError(msg) +          return obj @@ -460,7 +486,7 @@ class HyperlinkedIdentityField(Field):          slug = getattr(obj, self.slug_field, None)          if not slug: -            raise ValidationError('Could not resolve URL for field using view name "%s"' % view_name) +            raise Exception('Could not resolve URL for field using view name "%s"' % view_name)          kwargs = {self.slug_url_kwarg: slug}          try: @@ -474,4 +500,4 @@ class HyperlinkedIdentityField(Field):          except:              pass -        raise ValidationError('Could not resolve URL for field using view name "%s"' % view_name) +        raise Exception('Could not resolve URL for field using view name "%s"' % view_name) | 
