diff --git a/rest_framework/fields.py b/rest_framework/fields.py index a4e29a30a..c4acb00a5 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -504,6 +504,7 @@ class HyperlinkedRelatedField(RelatedField): except: raise ValueError("Hyperlinked field requires 'view_name' kwarg") + self.view_namespace = kwargs.pop('view_namespace',None) self.slug_field = kwargs.pop('slug_field', self.slug_field) default_slug_kwarg = self.slug_url_kwarg or self.slug_field self.pk_url_kwarg = kwargs.pop('pk_url_kwarg', self.pk_url_kwarg) @@ -519,7 +520,13 @@ class HyperlinkedRelatedField(RelatedField): return self.slug_field def to_native(self, obj): - view_name = self.view_name + if self.view_namespace: + view_name = "%(namespace)s:%(view)s" % { + 'view':self.view_name, + 'namespace':self.view_namespace + } + else: + view_name = self.view_name request = self.context.get('request', None) format = self.format or self.context.get('format', None) kwargs = {self.pk_url_kwarg: obj.pk} @@ -535,13 +542,13 @@ class HyperlinkedRelatedField(RelatedField): kwargs = {self.slug_url_kwarg: slug} try: - return reverse(self.view_name, kwargs=kwargs, request=request, format=format) + return reverse(view_name, kwargs=kwargs, request=request, format=format) except: pass kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug} try: - return reverse(self.view_name, kwargs=kwargs, request=request, format=format) + return reverse(view_name, kwargs=kwargs, request=request, format=format) except: pass @@ -608,6 +615,7 @@ class HyperlinkedIdentityField(Field): # TODO: Make view_name mandatory, and have the # HyperlinkedModelSerializer set it on-the-fly self.view_name = kwargs.pop('view_name', None) + self.view_namespace = kwargs.pop('view_namespace', None) self.format = kwargs.pop('format', None) self.slug_field = kwargs.pop('slug_field', self.slug_field) @@ -620,7 +628,13 @@ class HyperlinkedIdentityField(Field): def field_to_native(self, obj, field_name): request = self.context.get('request', None) format = self.format or self.context.get('format', None) + view_namespace = self.view_namespace or self.parent.opts.view_namespace view_name = self.view_name or self.parent.opts.view_name + if view_namespace: + view_name = "%(namespace)s:%(view)s" % { + 'view':view_name, + 'namespace':view_namespace + } kwargs = {self.pk_url_kwarg: obj.pk} try: return reverse(view_name, kwargs=kwargs, request=request, format=format) @@ -634,13 +648,13 @@ class HyperlinkedIdentityField(Field): kwargs = {self.slug_url_kwarg: slug} try: - return reverse(self.view_name, kwargs=kwargs, request=request, format=format) + return reverse(view_name, kwargs=kwargs, request=request, format=format) except: pass kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug} try: - return reverse(self.view_name, kwargs=kwargs, request=request, format=format) + return reverse(view_name, kwargs=kwargs, request=request, format=format) except: pass diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 522878e47..23acfe0e0 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -473,6 +473,7 @@ class HyperlinkedModelSerializerOptions(ModelSerializerOptions): def __init__(self, meta): super(HyperlinkedModelSerializerOptions, self).__init__(meta) self.view_name = getattr(meta, 'view_name', None) + self.view_namespace = getattr(meta, 'view_namespace', None) class HyperlinkedModelSerializer(ModelSerializer): @@ -488,6 +489,8 @@ class HyperlinkedModelSerializer(ModelSerializer): super(HyperlinkedModelSerializer, self).__init__(*args, **kwargs) if self.opts.view_name is None: self.opts.view_name = self._get_default_view_name(self.opts.model) + if self.opts.view_namespace is None: + self.opts.view_namespace = self._get_default_view_namespace(self.opts.model) def _get_default_view_name(self, model): """ @@ -498,14 +501,21 @@ class HyperlinkedModelSerializer(ModelSerializer): 'app_label': model_meta.app_label, 'model_name': model_meta.object_name.lower() } - view_name = self._default_view_name % format_kwargs - if self._default_view_namespace: - return "%(namespace)s:%(view)s" % { - 'view': view_name, - 'namespace': self._default_view_namespace - } - else: - return view_name + return self._default_view_name % format_kwargs + + def _get_default_view_namespace(self, model): + """ + Return the view namespace to use if 'view_namespace' is not specified in 'Meta' + """ + if self._default_view_namespace is None: + return self._default_view_namespace + + model_meta = model._meta + format_kwargs = { + 'app_label': model_meta.app_label, + 'model_name': model_meta.object_name.lower() + } + return self._default_view_namespace % format_kwargs def get_pk_field(self, model_field): return None @@ -520,7 +530,8 @@ class HyperlinkedModelSerializer(ModelSerializer): queryset = rel._default_manager kwargs = { 'queryset': queryset, - 'view_name': self._get_default_view_name(rel) + 'view_name': self._get_default_view_name(rel), + 'view_namespace': self._get_default_view_namespace(rel) } if to_many: return ManyHyperlinkedRelatedField(**kwargs)