mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-28 08:59:54 +03:00
Allow serializer data to include related objects by object
When instantiating a serializer from cleaned data, the relational fields have been already converted into objects, which makes the fields invalid. Having a valid object as the value of a field is not necessarily considered valid, if the object is not in the given queryset. As such, this change adds a check to allow objects of the model type and in the queryset in lieu of the proper representation.
This commit is contained in:
parent
4a98533746
commit
4e561a4ac0
|
@ -250,7 +250,9 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
if self.pk_field is not None:
|
if isinstance(data, self.get_queryset().model):
|
||||||
|
data = data.pk
|
||||||
|
elif self.pk_field is not None:
|
||||||
data = self.pk_field.to_internal_value(data)
|
data = self.pk_field.to_internal_value(data)
|
||||||
try:
|
try:
|
||||||
return self.get_queryset().get(pk=data)
|
return self.get_queryset().get(pk=data)
|
||||||
|
@ -331,6 +333,12 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
|
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
|
if isinstance(data, self.get_queryset().model):
|
||||||
|
try:
|
||||||
|
return self.get_queryset().get(**{self.lookup_url_kwarg: getattr(data, self.lookup_field)})
|
||||||
|
except (ObjectDoesNotExist, ObjectValueError, ObjectTypeError):
|
||||||
|
self.fail('does_not_exist')
|
||||||
|
|
||||||
request = self.context.get('request', None)
|
request = self.context.get('request', None)
|
||||||
try:
|
try:
|
||||||
http_prefix = data.startswith(('http:', 'https:'))
|
http_prefix = data.startswith(('http:', 'https:'))
|
||||||
|
|
|
@ -116,6 +116,10 @@ class TestPrimaryKeyRelatedField(APISimpleTestCase):
|
||||||
instance = field.to_internal_value(self.instance.pk)
|
instance = field.to_internal_value(self.instance.pk)
|
||||||
assert instance is self.instance
|
assert instance is self.instance
|
||||||
|
|
||||||
|
def test_pk_related_object_given(self):
|
||||||
|
instance = self.field.to_internal_value(self.instance)
|
||||||
|
assert instance is self.queryset.items[2]
|
||||||
|
|
||||||
|
|
||||||
class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
|
class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -216,6 +220,11 @@ class TestHyperlinkedRelatedField(APISimpleTestCase):
|
||||||
|
|
||||||
def hyperlinked_related_queryset_error(self, exc_type):
|
def hyperlinked_related_queryset_error(self, exc_type):
|
||||||
class QuerySet:
|
class QuerySet:
|
||||||
|
class FakeObject:
|
||||||
|
pass
|
||||||
|
|
||||||
|
model = FakeObject
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
raise exc_type
|
raise exc_type
|
||||||
|
|
||||||
|
@ -235,6 +244,10 @@ class TestHyperlinkedRelatedField(APISimpleTestCase):
|
||||||
def test_hyperlinked_related_queryset_value_error(self):
|
def test_hyperlinked_related_queryset_value_error(self):
|
||||||
self.hyperlinked_related_queryset_error(ValueError)
|
self.hyperlinked_related_queryset_error(ValueError)
|
||||||
|
|
||||||
|
def test_hyperlinked_related_object_given(self):
|
||||||
|
instance = self.field.to_internal_value(self.queryset.items[2])
|
||||||
|
assert instance is self.queryset.items[2]
|
||||||
|
|
||||||
|
|
||||||
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -322,6 +322,11 @@ class TestHyperlinkedRelatedField(URLPatternsTestCase, APITestCase):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
class MockQueryset:
|
class MockQueryset:
|
||||||
|
class MockObject:
|
||||||
|
pass
|
||||||
|
|
||||||
|
model = MockObject
|
||||||
|
|
||||||
def get(self, pk):
|
def get(self, pk):
|
||||||
return 'object %s' % pk
|
return 'object %s' % pk
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ class MockObject:
|
||||||
|
|
||||||
|
|
||||||
class MockQueryset:
|
class MockQueryset:
|
||||||
|
model = MockObject
|
||||||
|
|
||||||
def __init__(self, iterable):
|
def __init__(self, iterable):
|
||||||
self.items = iterable
|
self.items = iterable
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user