Django Rest Framework 忽略自定义字段
Django Rest Framework ignoring custom field
我有一个带有可为空布尔字段的模型,我希望以一种将输出中的 null
转换为 false
.
的方式进行序列化
我的模特:
class UserPreferences(models.Model):
receive_push_notifications = models.BooleanField(
null=True, blank=True,
help_text=("Receive push notifications))
我正在尝试使用这样的自定义字段:
class StrictlyBooleanField(serializers.Field):
def to_representation(self, value):
# Force None to False
return bool(value)
def to_internal_value(self, data):
return bool(data)
class UserPreferencesSerializer(serializers.ModelSerializer):
class Meta(object):
model = UserPreferences
fields = ('receive_push_notifications',)
receive_push_notifications = StrictlyBooleanField()
但这不起作用,我仍然在 API 回复中看到 null
。
我想我一定是在连接它时遗漏了一些简单的东西,因为如果我将我的 to_representation
替换为:
,我什至不会收到错误消息
def to_representation(self, value):
raise
DRF 似乎根本没有调用我的方法...我在这里缺少什么?
说明
查看rest framework的Serializer
的to_representation
方法后,您会发现它遍历了所有字段并为每个字段调用了field.get_attribute
方法。如果从该方法中编辑的值 return 是 None
,它会完全跳过调用 field.to_representation
并将 None
设置为字段值。
# Serializer's to_representation method
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
# We skip `to_representation` for `None` values so that fields do
# not have to explicitly deal with that case.
#
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
解决方案
如果值为 None
,则通过调用 super().get_attribute
和 return False
覆盖 field.get_attribute
class StrictlyBooleanField(serializers.Field):
def get_attribute(self, instance):
attribute = super().get_attribute(instance)
return bool(attribute)
def to_representation(self, value):
return value
def to_internal_value(self, data):
return bool(data)
您可以在序列化程序中编写一个简单的函数
class UserPreferencesSerializer(serializers.ModelSerializer):
yourField = serializers.SerializerMethodField(read_only=True)
class Meta(object):
model = UserPreferences
fields = ['receive_push_notifications', 'yourField']
def get_yourField(self, obj):
if obj.receive_push_notifications == null:
return False
else:
return True
我有一个带有可为空布尔字段的模型,我希望以一种将输出中的 null
转换为 false
.
我的模特:
class UserPreferences(models.Model):
receive_push_notifications = models.BooleanField(
null=True, blank=True,
help_text=("Receive push notifications))
我正在尝试使用这样的自定义字段:
class StrictlyBooleanField(serializers.Field):
def to_representation(self, value):
# Force None to False
return bool(value)
def to_internal_value(self, data):
return bool(data)
class UserPreferencesSerializer(serializers.ModelSerializer):
class Meta(object):
model = UserPreferences
fields = ('receive_push_notifications',)
receive_push_notifications = StrictlyBooleanField()
但这不起作用,我仍然在 API 回复中看到 null
。
我想我一定是在连接它时遗漏了一些简单的东西,因为如果我将我的 to_representation
替换为:
def to_representation(self, value):
raise
DRF 似乎根本没有调用我的方法...我在这里缺少什么?
说明
查看rest framework的Serializer
的to_representation
方法后,您会发现它遍历了所有字段并为每个字段调用了field.get_attribute
方法。如果从该方法中编辑的值 return 是 None
,它会完全跳过调用 field.to_representation
并将 None
设置为字段值。
# Serializer's to_representation method
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
# We skip `to_representation` for `None` values so that fields do
# not have to explicitly deal with that case.
#
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
解决方案
如果值为 None
super().get_attribute
和 return False
覆盖 field.get_attribute
class StrictlyBooleanField(serializers.Field):
def get_attribute(self, instance):
attribute = super().get_attribute(instance)
return bool(attribute)
def to_representation(self, value):
return value
def to_internal_value(self, data):
return bool(data)
您可以在序列化程序中编写一个简单的函数
class UserPreferencesSerializer(serializers.ModelSerializer):
yourField = serializers.SerializerMethodField(read_only=True)
class Meta(object):
model = UserPreferences
fields = ['receive_push_notifications', 'yourField']
def get_yourField(self, obj):
if obj.receive_push_notifications == null:
return False
else:
return True