Django REST Framework:如何用空字符串替换 null?

Posted

技术标签:

【中文标题】Django REST Framework:如何用空字符串替换 null?【英文标题】:Django REST Framework: how to substitute null with empty string? 【发布时间】:2019-02-09 15:46:30 【问题描述】:

我有一个具有以下 ImageField 类型的模型:

class Attendance(models.Model):
    face_image = models.ImageField(, blank=True, null=True, storage=MediaStorage())

基于模型的序列化器

class AttendanceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Attendance
        fields = ('id','face_image')

但是如果 imagefield 为 null,则显示如下

Its now showing like this in the json

  
    "id": 1,
    "face_image": null
  

如果 face_image (ImageField) 为 None,它将显示输出为 null。我想要的是将 null 替换为像这样的空字符串 ""

【问题讨论】:

【参考方案1】:

覆盖AttendanceSerializerto_representation()方法为,

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ('id', 'face_image')

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if not data['face_image']:
            data['face_image'] = ""
        return data

更新(2019 年 11 月 3 日)

我有很多字段,我为所有字段重复此代码并不是一个好主意,难道没有更好的方法来为所有字段执行此操作吗?

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ('id', 'face_image')

    def to_representation(self, instance):
        my_fields = 'field_1', 'field_2', 'field_3', 'field_4', 'field_5'
        data = super().to_representation(instance)
        for field in my_fields:
            try:
                if not data[field]:
                    data[field] = ""
            except KeyError:
                pass
        return data

【讨论】:

我有很多字段,我对所有字段重复此代码并不是一个好主意,难道没有更好的方法来为所有字段执行此操作吗?【参考方案2】:

您可以使用 SerializerMethodField。

class AttendanceSerializer(serializers.ModelSerializer):

    face_image = serializers.SerializerMethodField()

    class Meta: 
        model = Attendance
        fields = ('id', 'face_image')

    def get_face_image(self, instance):
        return (instance.face_image.url if instance.face_image else '')

【讨论】:

我认为你打破了这个解决方案的创建和更新方法。 你是什么意思? @BearBrown 正如@BearBrown 所说,SerializerMethodField 可能会在写入数据时出现问题【参考方案3】:

序列化程序元中提到的所有字段的迭代代码:

def to_representation(self, instance):
    data = super().to_representation(instance)
    for key, value in data.items():
        try:
            if not value:
                data[key] = ""
        except KeyError:
            pass
    return data

【讨论】:

【参考方案4】:

为了补充 JPG 的答案,这里有一个 mixin,它允许更轻松地重用覆盖 to_representation 方法的逻辑。它还确保值是 None 而不仅仅是 falsy

class ConvertNoneToStringSerializerMixin():
    """
    Mixin to convert None to empty strings.

    This must be added as the first inherited class. The property `Meta.none_to_str_fields` must
    be defined in order for this to have any effect. This only applies to representations,
    when we export our instance data, not when we acquire and validate data.
    """
    def get_none_to_str_fields(self):
        meta = getattr(self, 'Meta', None)
        return getattr(meta, 'none_to_str_fields', [])

    def to_representation(self, instance):
        fields = self.get_none_to_str_fields()
        data = super().to_representation(instance)

        if not fields or not isinstance(data, dict):
            return data

        for field in fields:
            if field in data and data[field] is None:
                data[field] = ''
        return data

这就是你将如何使用它:

class AttendanceSerializer(ConvertNoneToStringSerializerMixin, serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ('id', 'face_image')
        none_to_str_fields = ('face_image', )

另外,对于那些想知道的人,我们不能覆盖 Field 本身的 to_representation 方法,因为当值为 None 时,Serializer 的核心实现将跳过从字段中调用 to_representation。因此,重写序列化器是实现此目的的唯一方法。

【讨论】:

【参考方案5】:

您可以自定义一个序列化器字段并将其用作 ImageField 的默认 ModelSerializer 字段映射。

注意:以下代码 sn-p 应在序列化程序类之前加载。

from rest_framework import serializers
from django.db import models


class MyImageField(serializers.ImageField):
    def __init__(self, *args, **kwargs):
        self.null_as_blank = kwargs.pop('null_as_blank', True)
        if self.null_as_blank:
            kwargs['allow_blank'] = True
        super().__init__(*args, **kwargs)

    def to_internal_value(self, data):
        value = super().to_internal_value(data)
        # Handle deserializer, change blank value back to null.
        if self.null_as_blank and value == '':
            value = None
        return value

    def to_representation(self, value):
        value = super().to_internal_value(value)
        if self.null_as_blank and value is None:
            value = ''
        return value


serializers.ModelSerializer.serializer_field_mapping[models.ImageField] = MyImageField

【讨论】:

以上是关于Django REST Framework:如何用空字符串替换 null?的主要内容,如果未能解决你的问题,请参考以下文章

django-rest-framework 如何处理多个 URL 参数?

Django Rest Framework api如何为所有人添加身份验证权限

如何处理 django-rest-framework 中 url 模式中的外键关系

Django Rest Framework:在 ViewSet 上打开分页(如 ModelViewSet 分页)

Django Rest Framework - 如何为所有 ModelSerializer 字段创建自定义错误消息?

使用 django-rest-framework-simplejwt 注册后返回令牌