Allow relative style hyperlinked URLs

This commit is contained in:
Tom Christie 2016-06-02 15:03:17 +01:00
parent 9c996d7d2a
commit 75751cc64e
3 changed files with 34 additions and 4 deletions

View File

@ -678,6 +678,25 @@ You can explicitly include the primary key by adding it to the `fields` option,
model = Account model = Account
fields = ('url', 'id', 'account_name', 'users', 'created') fields = ('url', 'id', 'account_name', 'users', 'created')
## Absolute and relative URLs
When instantiating a `HyperlinkedModelSerializer` you must include the current
`request` in the serializer context, for example:
serializer = AccountSerializer(queryset, context={'request': request})
Doing so will ensure that the hyperlinks can include an appropriate hostname,
so that the resulting representation uses fully qualified URLs, such as:
http://api.example.com/accounts/1/
Rather than relative URLs, such as:
/accounts/1/
If you *do* want to use relative URLs, you should explicitly pass `{'request': None}`
in the serializer context.
## How hyperlinked views are determined ## How hyperlinked views are determined
There needs to be a way of determining which views should be used for hyperlinking to model instances. There needs to be a way of determining which views should be used for hyperlinking to model instances.

View File

@ -325,15 +325,15 @@ class HyperlinkedRelatedField(RelatedField):
self.fail('does_not_exist') self.fail('does_not_exist')
def to_representation(self, value): def to_representation(self, value):
request = self.context.get('request', None) assert 'request' in self.context, (
format = self.context.get('format', None)
assert request is not None, (
"`%s` requires the request in the serializer" "`%s` requires the request in the serializer"
" context. Add `context={'request': request}` when instantiating " " context. Add `context={'request': request}` when instantiating "
"the serializer." % self.__class__.__name__ "the serializer." % self.__class__.__name__
) )
request = self.context['request']
format = self.context.get('format', None)
# By default use whatever format is given for the current context # By default use whatever format is given for the current context
# unless the target is a different type to the source. # unless the target is a different type to the source.
# #

View File

@ -82,6 +82,17 @@ class HyperlinkedManyToManyTests(TestCase):
for target in ManyToManyTarget.objects.all(): for target in ManyToManyTarget.objects.all():
source.targets.add(target) source.targets.add(target)
def test_relative_hyperlinks(self):
queryset = ManyToManySource.objects.all()
serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': None})
expected = [
{'url': '/manytomanysource/1/', 'name': 'source-1', 'targets': ['/manytomanytarget/1/']},
{'url': '/manytomanysource/2/', 'name': 'source-2', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/']},
{'url': '/manytomanysource/3/', 'name': 'source-3', 'targets': ['/manytomanytarget/1/', '/manytomanytarget/2/', '/manytomanytarget/3/']}
]
with self.assertNumQueries(4):
self.assertEqual(serializer.data, expected)
def test_many_to_many_retrieve(self): def test_many_to_many_retrieve(self):
queryset = ManyToManySource.objects.all() queryset = ManyToManySource.objects.all()
serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request}) serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request})