mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-31 18:40:07 +03:00
Add a settings based override of relative vs. absolute URL behavior as well as the URL_FIELD_NAME.
This commit is contained in:
parent
d64be3f079
commit
c03614df28
|
@ -10,6 +10,7 @@ from django.http import Http404
|
|||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.request import clone_request
|
||||
from rest_framework.settings import api_settings
|
||||
import warnings
|
||||
|
||||
|
||||
|
@ -59,7 +60,7 @@ class CreateModelMixin(object):
|
|||
|
||||
def get_success_headers(self, data):
|
||||
try:
|
||||
return {'Location': data['url']}
|
||||
return {'Location': data[api_settings.URL_FIELD_NAME]}
|
||||
except (TypeError, KeyError):
|
||||
return {}
|
||||
|
||||
|
|
|
@ -335,6 +335,7 @@ class HyperlinkedRelatedField(RelatedField):
|
|||
|
||||
self.lookup_field = kwargs.pop('lookup_field', self.lookup_field)
|
||||
self.format = kwargs.pop('format', None)
|
||||
self.force_absolute = kwargs.pop('absolute', False)
|
||||
|
||||
# These are pending deprecation
|
||||
if 'pk_url_kwarg' in kwargs:
|
||||
|
@ -364,7 +365,10 @@ class HyperlinkedRelatedField(RelatedField):
|
|||
lookup_field = getattr(obj, self.lookup_field)
|
||||
kwargs = {self.lookup_field: lookup_field}
|
||||
try:
|
||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
return reverse(
|
||||
view_name, kwargs=kwargs, request=request,
|
||||
format=format, force_absolute=self.force_absolute
|
||||
)
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
|
||||
|
@ -374,7 +378,10 @@ class HyperlinkedRelatedField(RelatedField):
|
|||
pk = obj.pk
|
||||
kwargs = {self.pk_url_kwarg: pk}
|
||||
try:
|
||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
return reverse(
|
||||
view_name, kwargs=kwargs, request=request,
|
||||
format=format, force_absolute=self.force_absolute
|
||||
)
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
|
||||
|
@ -383,7 +390,10 @@ class HyperlinkedRelatedField(RelatedField):
|
|||
# Only try slug if it corresponds to an attribute on the object.
|
||||
kwargs = {self.slug_url_kwarg: slug}
|
||||
try:
|
||||
ret = reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
ret = reverse(
|
||||
view_name, kwargs=kwargs, request=request,
|
||||
format=format, force_absolute=self.force_absolute
|
||||
)
|
||||
if self.slug_field == 'slug' and self.slug_url_kwarg == 'slug':
|
||||
# If the lookup succeeds using the default slug params,
|
||||
# then `slug_field` is being used implicitly, and we
|
||||
|
@ -506,6 +516,7 @@ class HyperlinkedIdentityField(Field):
|
|||
self.format = kwargs.pop('format', None)
|
||||
lookup_field = kwargs.pop('lookup_field', None)
|
||||
self.lookup_field = lookup_field or self.lookup_field
|
||||
self.force_absolute = kwargs.pop('force_absolute', False)
|
||||
|
||||
# These are pending deprecation
|
||||
if 'pk_url_kwarg' in kwargs:
|
||||
|
@ -570,7 +581,10 @@ class HyperlinkedIdentityField(Field):
|
|||
lookup_field = getattr(obj, self.lookup_field)
|
||||
kwargs = {self.lookup_field: lookup_field}
|
||||
try:
|
||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
return reverse(
|
||||
view_name, kwargs=kwargs, request=request,
|
||||
format=format, force_absolute=self.force_absolute
|
||||
)
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
|
||||
|
@ -579,7 +593,10 @@ class HyperlinkedIdentityField(Field):
|
|||
# Otherwise, the default `lookup_field = 'pk'` has us covered.
|
||||
kwargs = {self.pk_url_kwarg: obj.pk}
|
||||
try:
|
||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
return reverse(
|
||||
view_name, kwargs=kwargs, request=request,
|
||||
format=format, force_absolute=self.force_absolute
|
||||
)
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
|
||||
|
@ -588,7 +605,10 @@ class HyperlinkedIdentityField(Field):
|
|||
# Only use slug lookup if a slug field exists on the model
|
||||
kwargs = {self.slug_url_kwarg: slug}
|
||||
try:
|
||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
return reverse(
|
||||
view_name, kwargs=kwargs, request=request,
|
||||
format=format, force_absolute=self.force_absolute
|
||||
)
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@ Provide reverse functions that return fully qualified URLs
|
|||
from __future__ import unicode_literals
|
||||
from django.core.urlresolvers import reverse as django_reverse
|
||||
from django.utils.functional import lazy
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
|
||||
def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
|
||||
def reverse(viewname, args=None, kwargs=None, request=None, format=None, force_absolute=False, **extra):
|
||||
"""
|
||||
Same as `django.core.urlresolvers.reverse`, but optionally takes a request
|
||||
and returns a fully qualified URL, using the request to get the base URL.
|
||||
|
@ -15,6 +16,9 @@ def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra
|
|||
kwargs = kwargs or {}
|
||||
kwargs['format'] = format
|
||||
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
|
||||
|
||||
if api_settings.RELATIVE_URLS and not force_absolute:
|
||||
return url
|
||||
if request:
|
||||
return request.build_absolute_uri(url)
|
||||
return url
|
||||
|
|
|
@ -893,7 +893,7 @@ class HyperlinkedModelSerializerOptions(ModelSerializerOptions):
|
|||
super(HyperlinkedModelSerializerOptions, self).__init__(meta)
|
||||
self.view_name = getattr(meta, 'view_name', None)
|
||||
self.lookup_field = getattr(meta, 'lookup_field', None)
|
||||
self.url_field_name = getattr(meta, 'url_field_name', 'url')
|
||||
self.url_field_name = getattr(meta, 'url_field_name', api_settings.URL_FIELD_NAME)
|
||||
|
||||
|
||||
class HyperlinkedModelSerializer(ModelSerializer):
|
||||
|
|
|
@ -81,6 +81,8 @@ DEFAULTS = {
|
|||
'URL_FORMAT_OVERRIDE': 'format',
|
||||
|
||||
'FORMAT_SUFFIX_KWARG': 'format',
|
||||
'URL_FIELD_NAME': 'url',
|
||||
'RELATIVE_URLS': False,
|
||||
|
||||
# Input and output formats
|
||||
'DATE_INPUT_FORMATS': (
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.test import TestCase
|
|||
from django.test.client import RequestFactory
|
||||
from rest_framework import generics, status, serializers
|
||||
from rest_framework.compat import patterns, url
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo, OptionalRelationModel
|
||||
|
||||
factory = RequestFactory()
|
||||
|
@ -328,3 +329,44 @@ class TestOverriddenURLField(TestCase):
|
|||
serializer.data,
|
||||
{'title': 'New blog post', 'url': 'foo bar'}
|
||||
)
|
||||
|
||||
|
||||
class TestGlobalURLOverrides(TestCase):
|
||||
def setUp(self):
|
||||
api_settings.URL_FIELD_NAME = 'global_url_field'
|
||||
api_settings.RELATIVE_URLS = True
|
||||
|
||||
class StandardSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = BlogPost
|
||||
fields = ('title', 'global_url_field')
|
||||
self.Serializer = StandardSerializer
|
||||
self.obj = BlogPost.objects.create(title="New blog post")
|
||||
|
||||
def test_serializer_overridden_url_field_name(self):
|
||||
"""
|
||||
The url field name should respect overriding at the serializer level.
|
||||
"""
|
||||
class URLFieldNameSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = BlogPost
|
||||
fields = ('title', 'serializer_url_field')
|
||||
url_field_name = "serializer_url_field"
|
||||
serializer = URLFieldNameSerializer(self.obj)
|
||||
self.assertIn('serializer_url_field', serializer.data)
|
||||
|
||||
def test_globally_overridden_url_field_name(self):
|
||||
"""
|
||||
The url field name should respect overriding for all serializers.
|
||||
"""
|
||||
serializer = self.Serializer(self.obj)
|
||||
import pdb; pdb.set_trace()
|
||||
print serializer.data
|
||||
self.assertIn('global_url_field', serializer.data)
|
||||
|
||||
def test_relative_urls(self):
|
||||
"""
|
||||
Test whether url fields can be made relative across the board.
|
||||
"""
|
||||
serializer = self.Serializer(self.obj)
|
||||
self.assertTrue(serializer.data['global_url_field'].startswith('/'))
|
||||
|
|
Loading…
Reference in New Issue
Block a user