Commit ee1a9fce by Tom Christie Committed by GitHub

Merge pull request #5078 from rooterkyberian/issue-4748

add URL path unquote to HyperlinkedRelatedField.to_internal_value
parents 66e015c5 5e185aa2
...@@ -7,7 +7,9 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist ...@@ -7,7 +7,9 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.db.models import Manager from django.db.models import Manager
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.utils import six from django.utils import six
from django.utils.encoding import python_2_unicode_compatible, smart_text from django.utils.encoding import (
python_2_unicode_compatible, smart_text, uri_to_iri
)
from django.utils.six.moves.urllib import parse as urlparse from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -324,6 +326,8 @@ class HyperlinkedRelatedField(RelatedField): ...@@ -324,6 +326,8 @@ class HyperlinkedRelatedField(RelatedField):
if data.startswith(prefix): if data.startswith(prefix):
data = '/' + data[len(prefix):] data = '/' + data[len(prefix):]
data = uri_to_iri(data)
try: try:
match = resolve(data) match = resolve(data)
except Resolver404: except Resolver404:
......
import uuid import uuid
import pytest import pytest
from django.conf.urls import url
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.test import override_settings
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from rest_framework import serializers from rest_framework import serializers
...@@ -87,10 +89,21 @@ class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase): ...@@ -87,10 +89,21 @@ class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
assert representation == self.instance.pk.int assert representation == self.instance.pk.int
@override_settings(ROOT_URLCONF=[
url(r'^example/(?P<name>.+)/$', lambda: None, name='example'),
])
class TestHyperlinkedRelatedField(APISimpleTestCase): class TestHyperlinkedRelatedField(APISimpleTestCase):
def setUp(self): def setUp(self):
self.queryset = MockQueryset([
MockObject(pk=1, name='foobar'),
MockObject(pk=2, name='baz qux'),
])
self.field = serializers.HyperlinkedRelatedField( self.field = serializers.HyperlinkedRelatedField(
view_name='example', read_only=True) view_name='example',
lookup_field='name',
lookup_url_kwarg='name',
queryset=self.queryset,
)
self.field.reverse = mock_reverse self.field.reverse = mock_reverse
self.field._context = {'request': True} self.field._context = {'request': True}
...@@ -98,6 +111,20 @@ class TestHyperlinkedRelatedField(APISimpleTestCase): ...@@ -98,6 +111,20 @@ class TestHyperlinkedRelatedField(APISimpleTestCase):
representation = self.field.to_representation(MockObject(pk='')) representation = self.field.to_representation(MockObject(pk=''))
assert representation is None assert representation is None
def test_hyperlinked_related_lookup_exists(self):
instance = self.field.to_internal_value('http://example.org/example/foobar/')
assert instance is self.queryset.items[0]
def test_hyperlinked_related_lookup_url_encoded_exists(self):
instance = self.field.to_internal_value('http://example.org/example/baz%20qux/')
assert instance is self.queryset.items[1]
def test_hyperlinked_related_lookup_does_not_exist(self):
with pytest.raises(serializers.ValidationError) as excinfo:
self.field.to_internal_value('http://example.org/example/doesnotexist/')
msg = excinfo.value.detail[0]
assert msg == 'Invalid hyperlink - Object does not exist.'
class TestHyperlinkedIdentityField(APISimpleTestCase): class TestHyperlinkedIdentityField(APISimpleTestCase):
def setUp(self): def setUp(self):
......
...@@ -156,6 +156,7 @@ class TestCustomLookupFields(TestCase): ...@@ -156,6 +156,7 @@ class TestCustomLookupFields(TestCase):
""" """
def setUp(self): def setUp(self):
RouterTestModel.objects.create(uuid='123', text='foo bar') RouterTestModel.objects.create(uuid='123', text='foo bar')
RouterTestModel.objects.create(uuid='a b', text='baz qux')
def test_custom_lookup_field_route(self): def test_custom_lookup_field_route(self):
detail_route = notes_router.urls[-1] detail_route = notes_router.urls[-1]
...@@ -164,12 +165,19 @@ class TestCustomLookupFields(TestCase): ...@@ -164,12 +165,19 @@ class TestCustomLookupFields(TestCase):
def test_retrieve_lookup_field_list_view(self): def test_retrieve_lookup_field_list_view(self):
response = self.client.get('/example/notes/') response = self.client.get('/example/notes/')
assert response.data == [{"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}] assert response.data == [
{"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"},
{"url": "http://testserver/example/notes/a%20b/", "uuid": "a b", "text": "baz qux"},
]
def test_retrieve_lookup_field_detail_view(self): def test_retrieve_lookup_field_detail_view(self):
response = self.client.get('/example/notes/123/') response = self.client.get('/example/notes/123/')
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"} assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
def test_retrieve_lookup_field_url_encoded_detail_view_(self):
response = self.client.get('/example/notes/a%20b/')
assert response.data == {"url": "http://testserver/example/notes/a%20b/", "uuid": "a b", "text": "baz qux"}
class TestLookupValueRegex(TestCase): class TestLookupValueRegex(TestCase):
""" """
...@@ -211,6 +219,10 @@ class TestLookupUrlKwargs(TestCase): ...@@ -211,6 +219,10 @@ class TestLookupUrlKwargs(TestCase):
response = self.client.get('/example2/notes/fo/') response = self.client.get('/example2/notes/fo/')
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"} assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
def test_retrieve_lookup_url_encoded_kwarg_detail_view(self):
response = self.client.get('/example2/notes/foo%20bar/')
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
class TestTrailingSlashIncluded(TestCase): class TestTrailingSlashIncluded(TestCase):
def setUp(self): def setUp(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment