mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-04 20:40:14 +03:00
Merge de8742116a
into d34dfc3fac
This commit is contained in:
commit
c8ac7f6092
|
@ -429,6 +429,11 @@ class ModelField(WritableField):
|
||||||
"type": self.model_field.get_internal_type()
|
"type": self.model_field.get_internal_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
super(ModelField, self).validate(value)
|
||||||
|
if value is None and not self.model_field.null:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
|
||||||
##### Typed Fields #####
|
##### Typed Fields #####
|
||||||
|
|
||||||
|
@ -474,10 +479,7 @@ class CharField(WritableField):
|
||||||
self.validators.append(validators.MaxLengthValidator(max_length))
|
self.validators.append(validators.MaxLengthValidator(max_length))
|
||||||
|
|
||||||
def from_native(self, value):
|
def from_native(self, value):
|
||||||
if isinstance(value, six.string_types):
|
if value in validators.EMPTY_VALUES:
|
||||||
return value
|
|
||||||
|
|
||||||
if value is None:
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
return smart_text(value)
|
return smart_text(value)
|
||||||
|
|
|
@ -33,7 +33,7 @@ class RelatedField(WritableField):
|
||||||
many_widget = widgets.SelectMultiple
|
many_widget = widgets.SelectMultiple
|
||||||
form_field_class = forms.ChoiceField
|
form_field_class = forms.ChoiceField
|
||||||
many_form_field_class = forms.MultipleChoiceField
|
many_form_field_class = forms.MultipleChoiceField
|
||||||
null_values = (None, '', 'None')
|
null_values = (None, '', 'None', [], (), {})
|
||||||
|
|
||||||
cache_choices = False
|
cache_choices = False
|
||||||
empty_label = None
|
empty_label = None
|
||||||
|
@ -182,7 +182,7 @@ class RelatedField(WritableField):
|
||||||
if value in self.null_values:
|
if value in self.null_values:
|
||||||
if self.required:
|
if self.required:
|
||||||
raise ValidationError(self.error_messages['required'])
|
raise ValidationError(self.error_messages['required'])
|
||||||
into[(self.source or field_name)] = None
|
into[(self.source or field_name)] = [] if self.many else None
|
||||||
elif self.many:
|
elif self.many:
|
||||||
into[(self.source or field_name)] = [self.from_native(item) for item in value]
|
into[(self.source or field_name)] = [self.from_native(item) for item in value]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -18,6 +18,7 @@ import types
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from django.contrib.contenttypes.generic import GenericForeignKey
|
from django.contrib.contenttypes.generic import GenericForeignKey
|
||||||
from django.core.paginator import Page
|
from django.core.paginator import Page
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms import widgets
|
from django.forms import widgets
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
|
@ -912,9 +913,19 @@ class ModelSerializer(Serializer):
|
||||||
|
|
||||||
for field_name, field in self.fields.items():
|
for field_name, field in self.fields.items():
|
||||||
field_name = field.source or field_name
|
field_name = field.source or field_name
|
||||||
|
|
||||||
|
# PY3 compat problem with ManyToManyField & OneToOneField
|
||||||
|
# hasattr in PY2 catches all exceptions, but in PY3 it only looks
|
||||||
|
# for AttributeError
|
||||||
|
# @see: https://code.djangoproject.com/ticket/22839
|
||||||
|
try:
|
||||||
|
field_exists = hasattr(instance, field_name)
|
||||||
|
except (AttributeError, ValueError, ObjectDoesNotExist):
|
||||||
|
field_exists = False
|
||||||
|
|
||||||
if field_name in exclusions \
|
if field_name in exclusions \
|
||||||
and not field.read_only \
|
and not field.read_only \
|
||||||
and (field.required or hasattr(instance, field_name)) \
|
and (field.required or field_exists) \
|
||||||
and not isinstance(field, Serializer):
|
and not isinstance(field, Serializer):
|
||||||
exclusions.remove(field_name)
|
exclusions.remove(field_name)
|
||||||
return exclusions
|
return exclusions
|
||||||
|
|
|
@ -52,7 +52,7 @@ class CallableDefaultValueModel(RESTFrameworkModel):
|
||||||
|
|
||||||
|
|
||||||
class ManyToManyModel(RESTFrameworkModel):
|
class ManyToManyModel(RESTFrameworkModel):
|
||||||
rel = models.ManyToManyField(Anchor, help_text='Some help text.')
|
rel = models.ManyToManyField(Anchor, help_text='Some help text.', blank=True)
|
||||||
|
|
||||||
|
|
||||||
class ReadOnlyManyToManyModel(RESTFrameworkModel):
|
class ReadOnlyManyToManyModel(RESTFrameworkModel):
|
||||||
|
|
|
@ -3,6 +3,7 @@ General tests for relational fields.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django import get_version
|
from django import get_version
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
|
@ -43,12 +44,27 @@ class TestManyRelatedMixin(TestCase):
|
||||||
|
|
||||||
https://github.com/tomchristie/django-rest-framework/pull/632
|
https://github.com/tomchristie/django-rest-framework/pull/632
|
||||||
'''
|
'''
|
||||||
field = serializers.RelatedField(many=True, read_only=False)
|
field = serializers.RelatedField(many=True, read_only=False, required=False)
|
||||||
|
|
||||||
into = {}
|
into = {}
|
||||||
field.field_from_native({}, None, 'field_name', into)
|
field.field_from_native({}, None, 'field_name', into)
|
||||||
self.assertEqual(into['field_name'], [])
|
self.assertEqual(into['field_name'], [])
|
||||||
|
|
||||||
|
def test_missing_required_many_to_many_related_field(self):
|
||||||
|
'''
|
||||||
|
Missing but required many-to-many relationship should cause
|
||||||
|
ValidationError
|
||||||
|
'''
|
||||||
|
field = serializers.RelatedField(many=True, read_only=False)
|
||||||
|
|
||||||
|
into = {}
|
||||||
|
self.assertRaises(
|
||||||
|
ValidationError,
|
||||||
|
field.field_from_native,
|
||||||
|
{}, None, 'field_name', into
|
||||||
|
)
|
||||||
|
self.assertDictEqual(into, {})
|
||||||
|
|
||||||
|
|
||||||
# Regression tests for #694 (`source` attribute on related fields)
|
# Regression tests for #694 (`source` attribute on related fields)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user