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.

Reply via email to