diff options
| author | Tom Christie | 2014-01-12 06:52:40 -0800 |
|---|---|---|
| committer | Tom Christie | 2014-01-12 06:52:40 -0800 |
| commit | 07cff7b37f23489579ad9effeea9365725b7cc82 (patch) | |
| tree | 219a03e808f239c6ca7d5e270fb278b78788a0ad | |
| parent | 52686420f4bf866064ee88a15903665f14289394 (diff) | |
| parent | cd9a4194ea4f4dc0e43a34485cd8a27eba44a39a (diff) | |
| download | django-rest-framework-07cff7b37f23489579ad9effeea9365725b7cc82.tar.bz2 | |
Merge pull request #1348 from yprez/none-to-empty-string_2.4
Coerce None to empty string
| -rw-r--r-- | docs/api-guide/fields.md | 7 | ||||
| -rw-r--r-- | rest_framework/fields.py | 7 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 4 | ||||
| -rw-r--r-- | rest_framework/tests/test_serializer.py | 22 |
4 files changed, 35 insertions, 5 deletions
diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index e05c0306..83825350 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -157,23 +157,24 @@ Corresponds to `django.db.models.fields.BooleanField`. ## CharField A text representation, optionally validates the text to be shorter than `max_length` and longer than `min_length`. +If `allow_none` is `False` (default), `None` values will be converted to an empty string. Corresponds to `django.db.models.fields.CharField` or `django.db.models.fields.TextField`. -**Signature:** `CharField(max_length=None, min_length=None)` +**Signature:** `CharField(max_length=None, min_length=None, allow_none=False)` ## URLField Corresponds to `django.db.models.fields.URLField`. Uses Django's `django.core.validators.URLValidator` for validation. -**Signature:** `CharField(max_length=200, min_length=None)` +**Signature:** `CharField(max_length=200, min_length=None, allow_none=False)` ## SlugField Corresponds to `django.db.models.fields.SlugField`. -**Signature:** `CharField(max_length=50, min_length=None)` +**Signature:** `CharField(max_length=50, min_length=None, allow_none=False)` ## ChoiceField diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 5ee75235..16485b41 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -443,8 +443,9 @@ class CharField(WritableField): type_label = 'string' form_field_class = forms.CharField - def __init__(self, max_length=None, min_length=None, *args, **kwargs): + def __init__(self, max_length=None, min_length=None, allow_none=False, *args, **kwargs): self.max_length, self.min_length = max_length, min_length + self.allow_none = allow_none super(CharField, self).__init__(*args, **kwargs) if min_length is not None: self.validators.append(validators.MinLengthValidator(min_length)) @@ -452,7 +453,9 @@ class CharField(WritableField): self.validators.append(validators.MaxLengthValidator(max_length)) def from_native(self, value): - if isinstance(value, six.string_types) or value is None: + if value is None and not self.allow_none: + return '' + if isinstance(value, six.string_types): return value return smart_text(value) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index fa935306..cbf73fc3 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -804,6 +804,10 @@ class ModelSerializer(Serializer): issubclass(model_field.__class__, models.PositiveSmallIntegerField): kwargs['min_value'] = 0 + if model_field.null and \ + issubclass(model_field.__class__, (models.CharField, models.TextField)): + kwargs['allow_none'] = True + attribute_dict = { models.CharField: ['max_length'], models.CommaSeparatedIntegerField: ['max_length'], diff --git a/rest_framework/tests/test_serializer.py b/rest_framework/tests/test_serializer.py index 86f365de..6d9b85ee 100644 --- a/rest_framework/tests/test_serializer.py +++ b/rest_framework/tests/test_serializer.py @@ -1124,6 +1124,20 @@ class BlankFieldTests(TestCase): serializer = self.model_serializer_class(data={}) self.assertEqual(serializer.is_valid(), True) + def test_create_model_null_field_save(self): + """ + Regression test for #1330. + + https://github.com/tomchristie/django-rest-framework/pull/1330 + """ + serializer = self.model_serializer_class(data={'title': None}) + self.assertEqual(serializer.is_valid(), True) + + try: + serializer.save() + except Exception: + self.fail('Exception raised on save() after validation passes') + #test for issue #460 class SerializerPickleTests(TestCase): @@ -1490,6 +1504,7 @@ class AttributeMappingOnAutogeneratedFieldsTests(TestCase): image_field = models.ImageField(max_length=1024, blank=True) slug_field = models.SlugField(max_length=1024, blank=True) url_field = models.URLField(max_length=1024, blank=True) + nullable_char_field = models.CharField(max_length=1024, blank=True, null=True) class AMOAFSerializer(serializers.ModelSerializer): class Meta: @@ -1522,6 +1537,10 @@ class AttributeMappingOnAutogeneratedFieldsTests(TestCase): 'url_field': [ ('max_length', 1024), ], + 'nullable_char_field': [ + ('max_length', 1024), + ('allow_none', True), + ], } def field_test(self, field): @@ -1558,6 +1577,9 @@ class AttributeMappingOnAutogeneratedFieldsTests(TestCase): def test_url_field(self): self.field_test('url_field') + def test_nullable_char_field(self): + self.field_test('nullable_char_field') + class DefaultValuesOnAutogeneratedFieldsTests(TestCase): |
