From 4b77b3c5adcc147316629a01e05a3600d1d89d27 Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Wed, 2 Jan 2013 19:06:55 +0100 Subject: Move the urlparse lib compatibility to the compat file. --- rest_framework/relations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index fe8cbc44..33d3732f 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -12,7 +12,7 @@ except ImportError: from django.utils.encoding import smart_unicode as smart_text from rest_framework.fields import Field, WritableField from rest_framework.reverse import reverse -from urlparse import urlparse +from rest_framework.compat import urlparse ##### Relational fields ##### @@ -360,7 +360,7 @@ class HyperlinkedRelatedField(RelatedField): if value.startswith('http:') or value.startswith('https:'): # If needed convert absolute URLs to relative path - value = urlparse(value).path + value = urlparse.urlparse(value).path prefix = get_script_prefix() if value.startswith(prefix): value = '/' + value[len(prefix):] -- cgit v1.2.3 From 60250f22c8e144494f372338c16a2167cccb319d Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Thu, 3 Jan 2013 11:41:07 +0100 Subject: Move the various compat things to the compat module. --- rest_framework/relations.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 33d3732f..b7a6e0c1 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -6,13 +6,10 @@ from django.core.urlresolvers import resolve, get_script_prefix from django import forms from django.forms import widgets from django.forms.models import ModelChoiceIterator -try: - from django.utils.encoding import smart_text -except ImportError: - from django.utils.encoding import smart_unicode as smart_text from rest_framework.fields import Field, WritableField from rest_framework.reverse import reverse from rest_framework.compat import urlparse +from rest_framework.compat import smart_text ##### Relational fields ##### -- cgit v1.2.3 From eb3d4d0e93b07d245232685d4fe3ad78144ea933 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 16 Jan 2013 14:32:51 +0000 Subject: Drop bits of relations_slug tests which don't mirror existing tests. --- rest_framework/relations.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 5e4552b7..7ded3891 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -105,6 +105,9 @@ class RelatedField(WritableField): value = getattr(obj, self.source or field_name) except ObjectDoesNotExist: return None + + if value is None: + return None return self.to_native(value) def field_from_native(self, data, files, field_name, into): -- cgit v1.2.3 From 211bb89eecfadd6831a0c59852926f16ea6bf733 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jan 2013 21:29:21 +0000 Subject: Raise Validation Errors when relationships receive incorrect types. Fixes #590. --- rest_framework/relations.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 7ded3891..af63ceaa 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -177,7 +177,7 @@ class PrimaryKeyRelatedField(RelatedField): default_error_messages = { 'does_not_exist': _("Invalid pk '%s' - object does not exist."), - 'invalid': _('Invalid value.'), + 'incorrect_type': _('Incorrect type. Expected pk value, received %s.'), } # TODO: Remove these field hacks... @@ -208,7 +208,8 @@ class PrimaryKeyRelatedField(RelatedField): msg = self.error_messages['does_not_exist'] % smart_unicode(data) raise ValidationError(msg) except (TypeError, ValueError): - msg = self.error_messages['invalid'] + received = type(data).__name__ + msg = self.error_messages['incorrect_type'] % received raise ValidationError(msg) def field_to_native(self, obj, field_name): @@ -235,7 +236,7 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField): default_error_messages = { 'does_not_exist': _("Invalid pk '%s' - object does not exist."), - 'invalid': _('Invalid value.'), + 'incorrect_type': _('Incorrect type. Expected pk value, received %s.'), } def prepare_value(self, obj): @@ -275,7 +276,8 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField): msg = self.error_messages['does_not_exist'] % smart_unicode(data) raise ValidationError(msg) except (TypeError, ValueError): - msg = self.error_messages['invalid'] + received = type(data).__name__ + msg = self.error_messages['incorrect_type'] % received raise ValidationError(msg) ### Slug relationships @@ -333,7 +335,7 @@ class HyperlinkedRelatedField(RelatedField): '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.'), + 'incorrect_type': _('Incorrect type. Expected url string, received %s.'), } def __init__(self, *args, **kwargs): @@ -397,8 +399,8 @@ class HyperlinkedRelatedField(RelatedField): try: http_prefix = value.startswith('http:') or value.startswith('https:') except AttributeError: - msg = self.error_messages['invalid'] - raise ValidationError(msg) + msg = self.error_messages['incorrect_type'] + raise ValidationError(msg % type(value).__name__) if http_prefix: # If needed convert absolute URLs to relative path @@ -434,8 +436,8 @@ class HyperlinkedRelatedField(RelatedField): except ObjectDoesNotExist: raise ValidationError(self.error_messages['does_not_exist']) except (TypeError, ValueError): - msg = self.error_messages['invalid'] - raise ValidationError(msg) + msg = self.error_messages['incorrect_type'] + raise ValidationError(msg % type(value).__name__) return obj -- cgit v1.2.3 From 4eb5861f3676781493af29f8e9fd87ec22e591aa Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jan 2013 23:36:35 +0000 Subject: Starting migration from ManyField to Field(many=True) --- rest_framework/relations.py | 93 +++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 49 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index af63ceaa..8d3615ad 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -21,15 +21,20 @@ class RelatedField(WritableField): representation of the target. """ widget = widgets.Select + many_widget = widgets.SelectMultiple cache_choices = False empty_label = None default_read_only = True # TODO: Remove this + many = False def __init__(self, *args, **kwargs): self.queryset = kwargs.pop('queryset', None) self.null = kwargs.pop('null', False) + self.many = kwargs.pop('many', self.many) super(RelatedField, self).__init__(*args, **kwargs) self.read_only = kwargs.pop('read_only', self.default_read_only) + if self.many: + self.widget = self.many_widget def initialize(self, parent, field_name): super(RelatedField, self).initialize(parent, field_name) @@ -108,6 +113,9 @@ class RelatedField(WritableField): if value is None: return None + + if self.many: + return [self.to_native(item) for item in value.all()] return self.to_native(value) def field_from_native(self, data, files, field_name, into): @@ -115,7 +123,17 @@ class RelatedField(WritableField): return try: - value = data[field_name] + if self.many: + try: + # Form data + value = data.getlist(field_name) + if value == ['']: + value = [] + except AttributeError: + # Non-form data + value = data[field_name] + else: + value = data[field_name] except KeyError: if self.required: raise ValidationError(self.error_messages['required']) @@ -125,47 +143,12 @@ class RelatedField(WritableField): raise ValidationError('Value may not be null') elif value in (None, '') and self.null: into[(self.source or field_name)] = None + elif self.many: + into[(self.source or field_name)] = [self.from_native(item) for item in value] else: into[(self.source or field_name)] = self.from_native(value) -class ManyRelatedMixin(object): - """ - Mixin to convert a related field to a many related field. - """ - widget = widgets.SelectMultiple - - def field_to_native(self, obj, field_name): - value = getattr(obj, self.source or field_name) - return [self.to_native(item) for item in value.all()] - - def field_from_native(self, data, files, field_name, into): - if self.read_only: - return - - try: - # Form data - value = data.getlist(self.source or field_name) - except: - # Non-form data - value = data.get(self.source or field_name) - else: - if value == ['']: - value = [] - - into[field_name] = [self.from_native(item) for item in value] - - -class ManyRelatedField(ManyRelatedMixin, RelatedField): - """ - Base class for related model managers. - - If not overridden, this represents a to-many relationship, using the unicode - representations of the target, and is read-only. - """ - pass - - ### PrimaryKey relationships class PrimaryKeyRelatedField(RelatedField): @@ -227,6 +210,12 @@ class PrimaryKeyRelatedField(RelatedField): return self.to_native(pk) +class ManyRelatedField(RelatedField): + def __init__(self, *args, **kwargs): + kwargs['many'] = True + super(ManyRelatedField, self).__init__(*args, **kwargs) + + class ManyPrimaryKeyRelatedField(ManyRelatedField): """ Represents a to-many relationship as a pk value. @@ -314,10 +303,6 @@ class SlugRelatedField(RelatedField): raise ValidationError(msg) -class ManySlugRelatedField(ManyRelatedMixin, SlugRelatedField): - form_field_class = forms.MultipleChoiceField - - ### Hyperlinked relationships class HyperlinkedRelatedField(RelatedField): @@ -442,13 +427,6 @@ class HyperlinkedRelatedField(RelatedField): return obj -class ManyHyperlinkedRelatedField(ManyRelatedMixin, HyperlinkedRelatedField): - """ - Represents a to-many relationship, using hyperlinking. - """ - form_field_class = forms.MultipleChoiceField - - class HyperlinkedIdentityField(Field): """ Represents the instance, or a property on the instance, using hyperlinking. @@ -512,3 +490,20 @@ class HyperlinkedIdentityField(Field): pass raise Exception('Could not resolve URL for field using view name "%s"' % view_name) + + +### Old-style many classes for backwards compat + + + + +class ManySlugRelatedField(SlugRelatedField): + def __init__(self, *args, **kwargs): + kwargs['many'] = True + super(ManySlugRelatedField, self).__init__(*args, **kwargs) + + +class ManyHyperlinkedRelatedField(HyperlinkedRelatedField): + def __init__(self, *args, **kwargs): + kwargs['many'] = True + super(ManyHyperlinkedRelatedField, self).__init__(*args, **kwargs) -- cgit v1.2.3 From fceacd830fcd3b67425dafd5b0e6dcc5b285b6ca Mon Sep 17 00:00:00 2001 From: Fernando Rocha Date: Tue, 29 Jan 2013 18:46:05 -0300 Subject: Fix processing of ManyToManyField when it is empty Signed-off-by: Fernando Rocha --- rest_framework/relations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index af63ceaa..dc0a73e6 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -148,7 +148,7 @@ class ManyRelatedMixin(object): value = data.getlist(self.source or field_name) except: # Non-form data - value = data.get(self.source or field_name) + value = data.get(self.source or field_name, []) else: if value == ['']: value = [] -- cgit v1.2.3 From 4601487248ef76537e5e3fda17ae7220191dbad9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 30 Jan 2013 12:41:18 +0000 Subject: Use many=True style for pk relations. --- rest_framework/relations.py | 91 ++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 64 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 8d3615ad..aee43206 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -22,6 +22,9 @@ class RelatedField(WritableField): """ widget = widgets.Select many_widget = widgets.SelectMultiple + form_field_class = forms.ChoiceField + many_form_field_class = forms.MultipleChoiceField + cache_choices = False empty_label = None default_read_only = True # TODO: Remove this @@ -156,7 +159,6 @@ class PrimaryKeyRelatedField(RelatedField): Represents a to-one relationship as a pk value. """ default_read_only = False - form_field_class = forms.ChoiceField default_error_messages = { 'does_not_exist': _("Invalid pk '%s' - object does not exist."), @@ -196,85 +198,38 @@ class PrimaryKeyRelatedField(RelatedField): raise ValidationError(msg) def field_to_native(self, obj, field_name): + if self.many: + # To-many relationship + try: + # Prefer obj.serializable_value for performance reasons + queryset = obj.serializable_value(self.source or field_name) + except AttributeError: + # RelatedManager (reverse relationship) + queryset = getattr(obj, self.source or field_name) + + # Forward relationship + return [self.to_native(item.pk) for item in queryset.all()] + + # To-one relationship try: # Prefer obj.serializable_value for performance reasons pk = obj.serializable_value(self.source or field_name) except AttributeError: # RelatedObject (reverse relationship) try: - obj = getattr(obj, self.source or field_name) + pk = getattr(obj, self.source or field_name).pk except ObjectDoesNotExist: return None - return self.to_native(obj.pk) - # Forward relationship - return self.to_native(pk) - - -class ManyRelatedField(RelatedField): - def __init__(self, *args, **kwargs): - kwargs['many'] = True - super(ManyRelatedField, self).__init__(*args, **kwargs) - - -class ManyPrimaryKeyRelatedField(ManyRelatedField): - """ - Represents a to-many relationship as a pk value. - """ - default_read_only = False - form_field_class = forms.MultipleChoiceField - - default_error_messages = { - 'does_not_exist': _("Invalid pk '%s' - object does not exist."), - 'incorrect_type': _('Incorrect type. Expected pk value, received %s.'), - } - - def prepare_value(self, obj): - return self.to_native(obj.pk) - - def label_from_instance(self, obj): - """ - Return a readable representation for use with eg. select widgets. - """ - desc = smart_unicode(obj) - ident = smart_unicode(self.to_native(obj.pk)) - if desc == ident: - return desc - return "%s - %s" % (desc, ident) - def to_native(self, pk): - return pk - - def field_to_native(self, obj, field_name): - try: - # Prefer obj.serializable_value for performance reasons - queryset = obj.serializable_value(self.source or field_name) - except AttributeError: - # RelatedManager (reverse relationship) - queryset = getattr(obj, self.source or field_name) - return [self.to_native(item.pk) for item in queryset.all()] # Forward relationship - return [self.to_native(item.pk) for item in queryset.all()] + return self.to_native(pk) - def from_native(self, data): - if self.queryset is None: - raise Exception('Writable related fields must include a `queryset` argument') - - try: - return self.queryset.get(pk=data) - except ObjectDoesNotExist: - msg = self.error_messages['does_not_exist'] % smart_unicode(data) - raise ValidationError(msg) - except (TypeError, ValueError): - received = type(data).__name__ - msg = self.error_messages['incorrect_type'] % received - raise ValidationError(msg) ### Slug relationships 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."), @@ -313,7 +268,6 @@ class HyperlinkedRelatedField(RelatedField): slug_field = 'slug' slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden default_read_only = False - form_field_class = forms.ChoiceField default_error_messages = { 'no_match': _('Invalid hyperlink - No URL match'), @@ -494,7 +448,16 @@ class HyperlinkedIdentityField(Field): ### Old-style many classes for backwards compat +class ManyRelatedField(RelatedField): + def __init__(self, *args, **kwargs): + kwargs['many'] = True + super(ManyRelatedField, self).__init__(*args, **kwargs) + +class ManyPrimaryKeyRelatedField(PrimaryKeyRelatedField): + def __init__(self, *args, **kwargs): + kwargs['many'] = True + super(ManyPrimaryKeyRelatedField, self).__init__(*args, **kwargs) class ManySlugRelatedField(SlugRelatedField): -- cgit v1.2.3 From e24d29ec05fd3fa7cc12533929dc1b68e9d56f9a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 30 Jan 2013 14:21:18 +0000 Subject: Tweak empty list implementation --- rest_framework/relations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 221c72fb..046b0db1 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -129,8 +129,8 @@ class RelatedField(WritableField): try: # Form data value = data.getlist(field_name) - if value == ['']: - value = [] + if value == [''] or value == []: + raise KeyError except AttributeError: # Non-form data value = data[field_name] -- cgit v1.2.3 From e4ac566625dcb2858ce15148e38595b49eedfa1b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 30 Jan 2013 20:33:50 +0000 Subject: Add dprecation warnings --- rest_framework/relations.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 046b0db1..d49ca39b 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -8,6 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework.fields import Field, WritableField from rest_framework.reverse import reverse from urlparse import urlparse +import warnings ##### Relational fields ##### @@ -26,23 +27,27 @@ class RelatedField(WritableField): cache_choices = False empty_label = None - default_read_only = True # TODO: Remove this + read_only = True many = False def __init__(self, *args, **kwargs): - # 'null' will be deprecated in favor of 'required' + # 'null' is to be deprecated in favor of 'required' if 'null' in kwargs: + warnings.warn('The `null` keyword argument is due to be deprecated. ' + 'Use the `required` keyword argument instead.', + PendingDeprecationWarning, stacklevel=2) kwargs['required'] = not kwargs.pop('null') self.queryset = kwargs.pop('queryset', None) self.many = kwargs.pop('many', self.many) - super(RelatedField, self).__init__(*args, **kwargs) - self.read_only = kwargs.pop('read_only', self.default_read_only) if self.many: self.widget = self.many_widget self.form_field_class = self.many_form_field_class + kwargs['read_only'] = kwargs.pop('read_only', self.read_only) + super(RelatedField, self).__init__(*args, **kwargs) + def initialize(self, parent, field_name): super(RelatedField, self).initialize(parent, field_name) if self.queryset is None and not self.read_only: @@ -157,7 +162,7 @@ class PrimaryKeyRelatedField(RelatedField): """ Represents a relationship as a pk value. """ - default_read_only = False + read_only = False default_error_messages = { 'does_not_exist': _("Invalid pk '%s' - object does not exist."), @@ -231,7 +236,7 @@ class SlugRelatedField(RelatedField): """ Represents a relationship using a unique field on the target. """ - default_read_only = False + read_only = False default_error_messages = { 'does_not_exist': _("Object with %s=%s does not exist."), @@ -269,7 +274,7 @@ class HyperlinkedRelatedField(RelatedField): pk_url_kwarg = 'pk' slug_field = 'slug' slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden - default_read_only = False + read_only = False default_error_messages = { 'no_match': _('Invalid hyperlink - No URL match'), @@ -390,6 +395,7 @@ class HyperlinkedIdentityField(Field): pk_url_kwarg = 'pk' slug_field = 'slug' slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden + read_only = True def __init__(self, *args, **kwargs): # TODO: Make view_name mandatory, and have the @@ -452,23 +458,35 @@ class HyperlinkedIdentityField(Field): class ManyRelatedField(RelatedField): def __init__(self, *args, **kwargs): + warnings.warn('`ManyRelatedField()` is due to be deprecated. ' + 'Use `RelatedField(many=True)` instead.', + PendingDeprecationWarning, stacklevel=2) kwargs['many'] = True super(ManyRelatedField, self).__init__(*args, **kwargs) class ManyPrimaryKeyRelatedField(PrimaryKeyRelatedField): def __init__(self, *args, **kwargs): + warnings.warn('`ManyPrimaryKeyRelatedField()` is due to be deprecated. ' + 'Use `PrimaryKeyRelatedField(many=True)` instead.', + PendingDeprecationWarning, stacklevel=2) kwargs['many'] = True super(ManyPrimaryKeyRelatedField, self).__init__(*args, **kwargs) class ManySlugRelatedField(SlugRelatedField): def __init__(self, *args, **kwargs): + warnings.warn('`ManySlugRelatedField()` is due to be deprecated. ' + 'Use `SlugRelatedField(many=True)` instead.', + PendingDeprecationWarning, stacklevel=2) kwargs['many'] = True super(ManySlugRelatedField, self).__init__(*args, **kwargs) class ManyHyperlinkedRelatedField(HyperlinkedRelatedField): def __init__(self, *args, **kwargs): + warnings.warn('`ManyHyperlinkedRelatedField()` is due to be deprecated. ' + 'Use `HyperlinkedRelatedField(many=True)` instead.', + PendingDeprecationWarning, stacklevel=2) kwargs['many'] = True super(ManyHyperlinkedRelatedField, self).__init__(*args, **kwargs) -- cgit v1.2.3 From f4f237e3ee02fef4fd5f389bf4fb3bbdd00173bd Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 1 Feb 2013 14:03:28 +0000 Subject: 3.2, 3.3 compat --- rest_framework/relations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index c4f854ef..dfa80fb7 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -311,7 +311,7 @@ class SlugRelatedField(RelatedField): return self.queryset.get(**{self.slug_field: data}) except ObjectDoesNotExist: raise ValidationError(self.error_messages['does_not_exist'] % - (self.slug_field, unicode(data))) + (self.slug_field, smart_text(data))) except (TypeError, ValueError): msg = self.error_messages['invalid'] raise ValidationError(msg) -- cgit v1.2.3 From b82227e517bb7baced840b29d04a545a7b7557ae Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 4 Feb 2013 20:38:18 +0000 Subject: remove broken import --- rest_framework/relations.py | 1 - 1 file changed, 1 deletion(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 93f19362..a946d961 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -9,7 +9,6 @@ from django.forms.models import ModelChoiceIterator from django.utils.translation import ugettext_lazy as _ from rest_framework.fields import Field, WritableField from rest_framework.reverse import reverse -from urlparse import urlparse from rest_framework.compat import urlparse from rest_framework.compat import smart_text import warnings -- cgit v1.2.3 From b052c92ac38f90e5b56cfd128cd4a488713c048e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 4 Feb 2013 20:55:35 +0000 Subject: Cleanup imports Mostly adding `from __future__ import unicode_literals` everywhere. --- rest_framework/relations.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index a946d961..ae4ef6b3 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,6 +1,4 @@ - from __future__ import unicode_literals - from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.urlresolvers import resolve, get_script_prefix from django import forms -- cgit v1.2.3 From bd7977eed79bd8fc4d9e73b6d848b0f0cd5a72ec Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Wed, 6 Feb 2013 13:05:17 +0000 Subject: Purge naked excepts. Most of these had obvious exceptions which would be thrown. Some I'm not sure about but they should at least catch only Exception so as not to ignore SystemExit and other inappropriate Error classes. --- rest_framework/relations.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index ae4ef6b3..48946e21 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,5 +1,5 @@ from __future__ import unicode_literals -from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.core.exceptions import ObjectDoesNotExist, ValidationError, NoReverseMatch from django.core.urlresolvers import resolve, get_script_prefix from django import forms from django.forms import widgets @@ -59,7 +59,7 @@ class RelatedField(WritableField): self.queryset = manager.related.model._default_manager.all() else: # Reverse self.queryset = manager.field.rel.to._default_manager.all() - except: + except Exception: raise msg = ('Serializer related fields must include a `queryset`' + ' argument or set `read_only=True') @@ -290,7 +290,7 @@ class HyperlinkedRelatedField(RelatedField): def __init__(self, *args, **kwargs): try: self.view_name = kwargs.pop('view_name') - except: + except KeyError: raise ValueError("Hyperlinked field requires 'view_name' kwarg") self.slug_field = kwargs.pop('slug_field', self.slug_field) @@ -317,7 +317,7 @@ class HyperlinkedRelatedField(RelatedField): kwargs = {self.pk_url_kwarg: pk} try: return reverse(view_name, kwargs=kwargs, request=request, format=format) - except: + except NoReverseMatch: pass slug = getattr(obj, self.slug_field, None) @@ -328,13 +328,13 @@ class HyperlinkedRelatedField(RelatedField): kwargs = {self.slug_url_kwarg: slug} try: return reverse(view_name, kwargs=kwargs, request=request, format=format) - except: + except NoReverseMatch: pass kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug} try: return reverse(view_name, kwargs=kwargs, request=request, format=format) - except: + except NoReverseMatch: pass raise Exception('Could not resolve URL for field using view name "%s"' % view_name) @@ -360,7 +360,7 @@ class HyperlinkedRelatedField(RelatedField): try: match = resolve(value) - except: + except Exception: raise ValidationError(self.error_messages['no_match']) if match.view_name != self.view_name: @@ -434,7 +434,7 @@ class HyperlinkedIdentityField(Field): try: return reverse(view_name, kwargs=kwargs, request=request, format=format) - except: + except NoReverseMatch: pass slug = getattr(obj, self.slug_field, None) @@ -445,13 +445,13 @@ class HyperlinkedIdentityField(Field): kwargs = {self.slug_url_kwarg: slug} try: return reverse(view_name, kwargs=kwargs, request=request, format=format) - except: + except NoReverseMatch: pass kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug} try: return reverse(view_name, kwargs=kwargs, request=request, format=format) - except: + except NoReverseMatch: pass raise Exception('Could not resolve URL for field using view name "%s"' % view_name) -- cgit v1.2.3 From 11610e7c3c4330b863c9da5d843b6d874c2958e9 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Wed, 6 Feb 2013 13:10:54 +0000 Subject: Try the correct NoReverseMatch location. --- rest_framework/relations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 48946e21..53fd646d 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals -from django.core.exceptions import ObjectDoesNotExist, ValidationError, NoReverseMatch -from django.core.urlresolvers import resolve, get_script_prefix +from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch from django import forms from django.forms import widgets from django.forms.models import ModelChoiceIterator -- cgit v1.2.3 From 41ac1e8f32491f50a5c784bb1cd1cfdba52f7072 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 12 Feb 2013 13:54:50 +0000 Subject: Raise warnings if 'request' not in context for hyperlinked fields. --- rest_framework/relations.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 53fd646d..24e8e15c 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -311,6 +311,13 @@ class HyperlinkedRelatedField(RelatedField): view_name = self.view_name request = self.context.get('request', None) format = self.format or self.context.get('format', None) + + if request is None: + warnings.warn("Using `HyperlinkedRelatedField` without including the " + "request in the serializer context is due to be deprecated. " + "Add `context={'request': request}` when instantiating the serializer.", + PendingDeprecationWarning, stacklevel=4) + pk = getattr(obj, 'pk', None) if pk is None: return @@ -420,6 +427,12 @@ class HyperlinkedIdentityField(Field): view_name = self.view_name or self.parent.opts.view_name kwargs = {self.pk_url_kwarg: obj.pk} + if request is None: + warnings.warn("Using `HyperlinkedIdentityField` without including the " + "request in the serializer context is due to be deprecated. " + "Add `context={'request': request}` when instantiating the serializer.", + PendingDeprecationWarning, stacklevel=4) + # By default use whatever format is given for the current context # unless the target is a different type to the source. # -- cgit v1.2.3 From 018298deb89628b39e1caeceecb414c1e27310da Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 12 Feb 2013 23:03:04 +0000 Subject: Relational fields use same field_to_native logic as regular fields. Fixes #637. Closes #638. --- rest_framework/relations.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 24e8e15c..0c108717 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -5,7 +5,7 @@ from django import forms from django.forms import widgets from django.forms.models import ModelChoiceIterator from django.utils.translation import ugettext_lazy as _ -from rest_framework.fields import Field, WritableField +from rest_framework.fields import Field, WritableField, get_component from rest_framework.reverse import reverse from rest_framework.compat import urlparse from rest_framework.compat import smart_text @@ -116,7 +116,16 @@ class RelatedField(WritableField): def field_to_native(self, obj, field_name): try: - value = getattr(obj, self.source or field_name) + if self.source == '*': + return self.to_native(obj) + + source = self.source or field_name + value = obj + + for component in source.split('.'): + value = get_component(value, component) + if value is None: + break except ObjectDoesNotExist: return None -- cgit v1.2.3 From 126a0f739ddb19ab2525618539b526d02330dbd5 Mon Sep 17 00:00:00 2001 From: Bouke Haarsma Date: Sun, 10 Mar 2013 21:02:34 +0100 Subject: Fixed #720 --- rest_framework/relations.py | 1 - 1 file changed, 1 deletion(-) (limited to 'rest_framework/relations.py') diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 0c108717..2a10e9af 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -235,7 +235,6 @@ class PrimaryKeyRelatedField(RelatedField): pk = getattr(obj, self.source or field_name).pk except ObjectDoesNotExist: return None - return self.to_native(obj.pk) # Forward relationship return self.to_native(pk) -- cgit v1.2.3