A vanilla ModelSerializer does not inherit the model field default values
unless db_index=true, which is okay for a POST request with JSON iff
Content-Type header is set to application/json.
But if the the content type is not set, then if the field is not in the
body of the POST, and the field is a boolean, then data is set to
default_empty_html
<https://github.com/encode/django-rest-framework/blob/3.5.4/rest_framework/fields.py#L646>
which
is "false".
Is this expected?
I apologize if this is the expected behavior!
Also I didn't try this with the newest versions of Django or DRF.
Versions:
rest_framework==3.5.4
django==1.10
python==2.7.13
Here is a vanilla django model with 2 fields, both have defaults, but one
is indexed (?):
class MyModel(models.Model):
field1 = models.BooleanField(
"indexed boolean field", default=False, db_index=True
)
field2 = models.BooleanField(default=True) # not indexed, no label
field3 = models.CharField('blah', max_length=100)
And a vanilla DRF model serializer
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
If I serialize a dictionary in the django shell, and call the serializer's
save() method, the correct defaults are used
from myapp.serializers import MyModelSerializer
x = {'field3': 'blah blah blah'}
s = MyModelSerializer(data=x)
s.is_valid()
o = s.save()
assert o.field1 # OK!
assert o.field2 # OK!
but if I use a test client, then it doesn't return the correct defaults
from rest_framework.test import APIClient
from django.contrib.auth.models import User
from django.conf import settings
settings.ALLOWED_HOSTS.append(u'testserver')
me = User.objects.get(username='me')
client = APIClient()
client.force_authenticate(user=me)
r = client.post('/mymodel/', x)
o = r.json()
assert o['field1'] # OK!
assert o['field2'] # FAILS!
if I use the test client with the correct content type, now it works again!
r = client.post('/mymodel/', x, format='json') # it's JSON not HTML!
o = r.json()
assert o['field1'] # OK!
assert o['field2'] # OK!
why? If I look at the fields in the serializer, only the indexed fields
have defaults, some of the fields have labels even though they aren't
explicitly defined in the model
s.fields
{
'field1': BooleanField(default=True, label='indexed boolean field',
required=False),
'field2': BooleanField(label='field2', required=False),
'field3': CharField(label='blah', max_length=100)
}
And the serializer fields are treated differently depending on whether or
not they are assumed be HTML based on a call to
rest_framework.utils.html.is_html_input
<https://github.com/encode/django-rest-framework/blob/3.5.4/rest_framework/utils/html.py>
which returns true if the data has the getlist attribute.
If the data is JSON or a Python dictionary, it doesn't have getlist, so
is_html_input returns False and the field's get_value(data)
<https://github.com/encode/django-rest-framework/blob/3.5.4/rest_framework/fields.py#L414>
call returns the empty field.
But if the data is posted without the JSON content type header, then since
the field has no default value, the default_empty_html value is returned
instead, which is False for boolean fields.
:-(
I guess the moral of the story is make sure you are using the correct
content type in your POST request, or you never know what you might get? If
anyone has any response that will make me feel less crazy, I would
appreciate it.
Thanks! And thanks Tom Christie and all of the other maintainers for DRF. I
love it!
:-)
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.