oxan / djangorestframework-dataclasses

Dataclasses serializer for Django REST framework
BSD 3-Clause "New" or "Revised" License
431 stars 28 forks source link

bool field with default of True actually defaults to False when using QueryDict #61

Closed ses4j closed 2 years ago

ses4j commented 2 years ago

If you pass a QueryDict to a serializer (such as request.GET), the bool somehow loses it's default value.

Demonstration:

from dataclasses import dataclass
from rest_framework_dataclasses.serializers import DataclassSerializer

@dataclass
class MyClass:
    my_bool: bool = True

class MySerializer(DataclassSerializer):
    class Meta:
        dataclass = MyClass

from django.http import QueryDict
from django.conf import settings

settings.configure()
s = MySerializer(data=QueryDict(encoding='utf8'))
assert s.is_valid()
assert s.data['my_bool'] is True, "this should be true but is false!"
oxan commented 2 years ago

~Which version are you using? If I try this in the REPL, it seems to work as expected:~ Ah, no, I see what you mean. That looks like a bug, indeed.

oxan commented 2 years ago

The root cause is this check, which triggers for a QueryDict but doesn't for a regular one. https://github.com/encode/django-rest-framework/blob/54d52c66fd221e9ff86d8b428c6c0178c0501606/rest_framework/fields.py#L422-L428

It seems that DRF assumes a missing value in a QueryDict is None or False. You can workaround it by setting the partial=True option, to only consider fields that are present.

ses4j commented 2 years ago

Ah, interesting. That's true, though I then lose validation on required params.

oxan commented 2 years ago

I don't think there's anything we can do about this, as this is caused by behaviour of DRF and is not specific to the DataclassSerializer, so I'll close this issue. You can workaround it by converting the QueryDict to a regular dict using the dict() method.