Django REST framework 源码剖析-序列化器详解(Serializers)

Django REST framework 源码剖析-序列化器详解(Serializers)

serializers

  • 序列化器允许将复杂数据 (如查询集和模型实例) 转换为可以轻松渲染成 JSON,XML 或其他内容类型的原生 Python 数据类型。序列化器还提供反序列化,在验证传入的数据之后允许解析数据转换回复杂类型。
  • REST framework 中的序列化器与 Django 的 Form 和 ModelForm 类非常相似。我们提供了一个 Serializer 类,它为您提供了强大的、通用的方法来控制响应的输出,以及一个 ModelSerializer 类,它为创建用于处理模型实例和查询集的序列化器提供了有用的快捷实现方式。
  • 序列化器就是一个中转站 主要进行对数据的转换,和对数据的校验(比如,前端传过来的数据格式正确之后,才可以保存到数据库)

Serializing

  • 测试方式创建django项目后终端运行 python3 manage.py shell

声明序列化器 (Declaring Serializers)

  • 声明类
from datetime import datetime

class Comment(object):
    def __init__(self, email, content, created=None):
        self.email = email
        self.content = content
        self.created = created or datetime.now()

  • 声明序列化器
from rest_framework import serializers

class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

序列化对象 (Serializing objects)

  • 数据序列化为字典
comment = Comment(email='leila@example.com', content='foo bar')
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
  • 数据渲染为json
from rest_framework.renderers import JSONRenderer

json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'

反序列化对象 (Deserializing objects)

from six import BytesIO
from rest_framework.parsers import JSONParser

stream = BytesIO(json)
data = JSONParser().parse(stream)
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

保存实例 (Saving instances)

  • 返回基于验证数据的完整对象实例
from rest_framework import serializers


class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

    def create(self, validated_data):
    	# return Comment.objects.create(**validated_data)
        return Comment(**validated_data)

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.content = validated_data.get('content', instance.content)
        instance.created = validated_data.get('created', instance.created)
        # instance.save()
        return instance
  • 创建
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
serializer.is_valid()
serializer.save()
  • 更新
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
serializer.is_valid()
serializer.save()
  • 重写save, 不进行创建和更新
from rest_framework import serializers


class ContactForm(serializers.Serializer):
    email = serializers.EmailField()
    message = serializers.CharField()

    def save(self):
        email = self.validated_data['email']
        message = self.validated_data['message']
        send_email(from=email, message=message)

验证 (Validation)

  • 校验数据格式、及提取返回异常信息
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}
  • 序列化器自定义字段级别的验证
from rest_framework import serializers


class BlogPostSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()

    def validate_title(self, value):
        """
        Check that the blog post is about Django.
        """
        if 'django' not in value.lower():
            raise serializers.ValidationError("Blog post is not about Django")
        return value
serializer = BlogPostSerializer(data={"title": "__title123", "content": "__content123"})
serializer.is_valid()
# False
serializer.errors
# {'title': [ErrorDetail(string='Blog post is not about Django', code='invalid')]}
  • 自定义对象级别的验证
from rest_framework import serializers

class EventSerializer(serializers.Serializer):
    description = serializers.CharField(max_length=100)
    start = serializers.DateTimeField()
    finish = serializers.DateTimeField()

    def validate(self, data):
        """
        Check that the start is before the stop.
        """
        if data['start'] > data['finish']:
            raise serializers.ValidationError("finish must occur after start")
        return data
serializer = EventSerializer(data={"description": "描述", "start": "2024-12-13 11:00:00", "finish": "2024-12-11 11:00:00"})
serializer.is_valid()
# False
serializer.errors
# {'non_field_errors': [ErrorDetail(string='finish must occur after start', code='invalid')]}
  • 自定义单字段验证器
from rest_framework import serializers

def multiple_of_ten(value):
    if value % 10 != 0:
        raise serializers.ValidationError('Not a multiple of ten')

class GameRecord(serializers.Serializer):
    score = serializers.IntegerField(validators=[multiple_of_ten])
serializer = GameRecord(data={"score": 11})
serializer.is_valid()
# False
serializer.errors
# {'score': [ErrorDetail(string='Not a multiple of ten', code='invalid')]}

访问初始数据和实例 (Accessing the initial data and instance)

  • 将初始化对象或者查询集传递给序列化器实例时,该对象将以 .instance 的形式提供。如果没有传递初始化对象,那么 .instance 属性将是 None。
  • 将数据传递给序列化器实例时,未修改的数据将以 .initial_data 的形式提供。如果 data 关键字参数未被传递,那么 .initial_data 属性将不存在。

部分更新 (Partial updates)

  • partial字段允许部分更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

处理嵌套对象 (Dealing with nested objects)

  • Serializer 类本身也是一种 Field,并且可以用来表示一个对象类型嵌套在另一个对象类型中的关系
from rest_framework import serializers


class UserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)

class CommentSerializer(serializers.Serializer):
    user = UserSerializer()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
  • 如果嵌套表示可以可选地接受 None 值,则应将 required=False 标志传递给嵌套的序列化器
from rest_framework import serializers


class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)  # May be an anonymous user.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
  • 如果嵌套表示应该是项目列表,则应将 many = True 标志传递给嵌套的序列化器
from rest_framework import serializers


class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)
    edits = EditItemSerializer(many=True)  # A nested list of 'edit' items.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

可写的嵌套表示 (Writable nested representations)

serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']}
  • 重写create方法, 处理嵌套对象创建用户
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user
  • 重写update方法, 处理嵌套对象更新用户
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        # 除非应用程序正确地强制始终设置该字段,否则就应该抛出一个需要处理的`DoesNotExist`。
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()

        profile.is_premium_member = profile_data.get(
            'is_premium_member',
            profile.is_premium_member
        )
        profile.has_support_contract = profile_data.get(
            'has_support_contract',
            profile.has_support_contract
         )
        profile.save()

        return instance
  • 在模型管理类中保存关联实例,自定义管理类
class UserManager(models.Manager):
    ...

    def create(self, username, email, is_premium_member=False, has_support_contract=False):
        user = User(username=username, email=email)
        user.save()
        profile = Profile(
            user=user,
            is_premium_member=is_premium_member,
            has_support_contract=has_support_contract
        )
        profile.save()
        return user
  • 序列化器调用自定义管理类
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
	    return User.objects.create(
	        username=validated_data['username'],
	        email=validated_data['email']
	        is_premium_member=validated_data['profile']['is_premium_member']
	        has_support_contract=validated_data['profile']['has_support_contract']
	    )

处理多个对象 (Dealing with multiple objects)

  • 序列化多个对象, many=True
from rest_framework import serializers


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ('id', 'title', 'author')
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
#     {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
#     {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
#     {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]

包括额外的上下文 (Including extra context)

  • 序列化器传递附加的上下文context, 序列化器中访问通过self.context 属性
serializer = AccountSerializer(account, context={'request': request})
serializer.data
# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}

ModelSerializer

  • 序列化器类紧密地映射到 Django 模型定义上
  • 根据模型自动为您生成一组字段
  • 自动为序列化器生成验证器
  • 包含默认简单实现的 .create() 和 .update() 方法
  • 模型上的任何关系如 (外键) 都将映射到 PrimaryKeyRelatedField
  • 默认情况下不包括反向关系
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')

指定要包含的字段 (Specifying which fields to include)

  • fields显示的指定字段
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
  • fields显示所有字段
class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__'
  • exclude指定不显示的字段
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        exclude = ('users',)

指定嵌套序列化 (Specifying nested serialization)

  • 默认序列化器使用主键进行关联,也可以使用 depth 选项轻松的生成嵌套关联,depth 选项应设置为一个整数值
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        depth = 1

显式指定字段 (Specifying fields explicitly)

  • 序列化器添加额外字段,或通过在类上声明字段来重写默认字段
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    groups = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Account

指定只读字段 (Specifying read only fields)

  • 模型中已经设置 editable=False 的字段和默认就被设置为只读的 AutoField 字段都不需要添加到 read_only_fields 选项中
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        read_only_fields = ('account_name',)
  • 只读字段是模型级别 unique_together 约束的一部分处理
from rest_framework import serializers


class AccountSerializer(serializers.ModelSerializer):
	user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')

附加关键字参数 (Additional keyword arguments)

  • 使用 extra_kwargs 选项在字段上指定任意附加关键字参数, 与 read_only_fields 的功能相同
from rest_framework import serializers


class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

关系字段 (Relational fields)

  • ModelSerializer 的默认是使用相关实例的主键

自定义字段映射 (Customizing field mappings)

  • Django 模型类到 REST framework 序列化器类的映射。重写此映射以更改用于每个模型类的默认序列化器类
serializer_field_mapping = {}
  • 重写此属性用于关联字段, 默认是PrimaryKeyRelatedField
serializer_related_field = ObjectField
  • 重写此属性用于任何 url 字段的序列化, 默认是HyperlinkedIdentityField
serializer_url_field = ObjectField
  • 重写此属性, 用于任何选择字段的序列化, 默认是ChoiceField
serializer_choice_field = ObjectField
  • 重写此方法, 调用以生成映射到标准模型字段的序列化器字段, 默认是serializer_field_mapping的映射
build_standard_field(self, field_name, model_field)
  • 重写此方法, 调用以生成映射到关系模型字段的序列化器字段, 默认是serializer_relational_field属性的序列化器类
build_relational_field(self, field_name, relation_info)
  • 重写此方法, 当设置了 depth 选项时, 调用以生成映射到关系模型字段的序列化器字段, 默认是ModelSerializer 或 HyperlinkedModelSerializer 动态创建嵌套的序列化器类
build_nested_field(self, field_name, relation_info, nested_depth)
  • 重写此方法, 调用以生成映射到模型类中的属性或零参数方法的序列化器字段, 默认实现返回 ReadOnlyField 类。
build_property_field(self, field_name, model_class)
  • 重写此方法, 调用为模型的 url 字段生成序列化器字段, 默认实现返回HyperlinkedIdentityField 类。
build_url_field(self, field_name, model_class)
  • 重写此方法, 若字段名称未映射到任何模型字段或模型属性时调用, 默认会引发错误
build_unknown_field(self, field_name, model_class)

HyperlinkedModelSerializer

  • HyperlinkedModelSerializer 类类似于 ModelSerializer 类,不同之处在于它使用超链接来表示关联关系而不是主键。
  • 默认情况下,序列化器将包含 url 字段而不是主键字段。
  • url 字段将使用 HyperlinkedIdentityField 序列化器字段表示,并且模型上的任何关系将使用 HyperlinkedRelatedField 序列化器字段表示。
  • 可以通过将主键添加到 fields 选项显式包含主键。
from rest_framework import serializers


class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('url', 'id', 'account_name', 'users', 'created')

绝对和相对 URL (Absolute and relative URLs)

  • 当实例化 HyperlinkedModelSerializer 时,必须在序列化器上下文中包含当前 request
  • 绝对URL
serializer = AccountSerializer(queryset, context={'request': request})
# 默认生成 http://api.example.com/accounts/1/
  • 相对URL
serializer = AccountSerializer(queryset, context={'request': None})
# 默认生成 /accounts/1/

如何确定超链接视图 (How hyperlinked views are determined)

  • 默认情况下,超链接预期对应于匹配样式 {model_name}-detail 的视图名,并通过 pk 关键字参数查找实例
  • 打印 HyperlinkedModelSerializer 实例的 repr 是特别有用的方式来检查关联关系预映射到哪些视图名称和查询字段
  • 在 extra_kwargs 设置中的 view_name 和 lookup_field 选项中的一个或两个来重写 URL 字段视图名称和查询字段
from rest_framework import serializers


class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('account_url', 'account_name', 'users', 'created')
        extra_kwargs = {
            'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},
            'users': {'lookup_field': 'username'}
        }
  • 显式设置序列化器上的字段, 用于确定超链接
from rest_framework import serializers


class AccountSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='accounts',
        lookup_field='slug'
    )
    users = serializers.HyperlinkedRelatedField(
        view_name='user-detail',
        lookup_field='username',
        many=True,
        read_only=True
    )

    class Meta:
        model = Account
        fields = ('url', 'account_name', 'users', 'created')

更改 URL 字段名称 (Changing the URL field name)

  • URL 字段的名称默认为 ‘url’, 可重写配置文件字段 URL_FIELD_NAME
URL_FIELD_NAME = "xxx"

ListSerializer

  • 类提供同时序列化和验证多个对象的行为
  • 不需要直接使用 ListSerializer, 在实例化序列化器时简单地传递 many=True即可
  • allow_empty默认为True, 如果要禁止空列表作为有效输入, 则设置allow_empty为False

自定义 ListSerializer 行为 (Customizing ListSerializer behavior)

  • 调用使用list_serializer_class
from rest_framework import serializers


class CustomListSerializer(serializers.ListSerializer):
    ...

class CustomSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = CustomListSerializer

自定义多重创建

  • 多个对象的创建默认实现是简单地为列表中的每个项目调用 .create() , 如果想要自定义该行为,那么您需要自定义当被传递 many=True 参数时使用的 ListSerializer 类中的 .create() 方法
from rest_framework import serializers


class BookListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        books = [Book(**item) for item in validated_data]
        return Book.objects.bulk_create(books)

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer
  • 自定义多个更新 (Customizing multiple update)
  • 默认隐式生成的 id 字段被标记为 read_only, 需要向实例序列化器显式添加 id 字段,才可以使用
from rest_framework import serializers


class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        # id->instance 和 id->data item 的映射。
        book_mapping = {book.id: book for book in instance}
        data_mapping = {item['id']: item for item in validated_data}

        # 执行创建和更新。
        ret = []
        for book_id, data in data_mapping.items():
            book = book_mapping.get(book_id, None)
            if book is None:
                ret.append(self.child.create(data))
            else:
                ret.append(self.child.update(book, data))

        # 执行删除
        for book_id, book in book_mapping.items():
            if book_id not in data_mapping:
                book.delete()

        return ret

class BookSerializer(serializers.Serializer):
    # 我们需要使用主键识别列表中的元素,
    # 所以在这里使用一个可写字段,而不是默认的只读字段。
    id = serializers.IntegerField()
    ...

    class Meta:
        list_serializer_class = BookListSerializer

BaseSerializer

  • BaseSerialAlgisher 类,可以用来方便地支持可选的序列化和反序列化样式
  • BaseSerializer 类不会在可浏览的 API 中生成 HTML 表单, 返回的数据不包括允许每个字段被渲染成合适的 HTML 输入的所有字段信息

只读 BaseSerializer 类(Read-only BaseSerializer classes)

  • Django 模型
from django.db import models


class HighScore(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    player_name = models.CharField(max_length=10)
    score = models.IntegerField()
  • 创建只读序列化器将 HighScore 实例转换为原始数据类型
# serializers.py
from rest_framework import serializers


class HighScoreSerializer(serializers.BaseSerializer):
    def to_representation(self, obj):
        return {
            'score': obj.score,
            'player_name': obj.player_name
        }
  • 序列化单个 HighScore
from rest_framework.decorators import api_view
from myproject.models import HighScore
from myproject.serializers import HighScoreSerializer


@api_view(['GET'])
def high_score(request, pk):
    instance = HighScore.objects.get(pk=pk)
    serializer = HighScoreSerializer(instance)
    return Response(serializer.data)
  • 序列化多个实例
from rest_framework.decorators import api_view
from myproject.models import HighScore
from myproject.serializers import HighScoreSerializer


@api_view(['GET'])
def all_high_scores(request):
    queryset = HighScore.objects.order_by('-score')
    serializer = HighScoreSerializer(queryset, many=True)
    return Response(serializer.data)

读写 BaseSerializer 类 (Read-write BaseSerializer classes)

from rest_framework import serializers

class HighScoreSerializer(serializers.BaseSerializer):
    def to_internal_value(self, data):
        score = data.get('score')
        player_name = data.get('player_name')

        # 执行数据验证。
        if not score:
            raise serializers.ValidationError({
                'score': 'This field is required.'
            })
        if not player_name:
            raise serializers.ValidationError({
                'player_name': 'This field is required.'
            })
        if len(player_name) > 10:
            raise serializers.ValidationError({
                'player_name': 'May not be more than 10 characters.'
            })

        # 返回验证值。这将作为可用的 `.validated_data` 属性。
        return {
            'score': int(score),
            'player_name': player_name
        }

    def to_representation(self, obj):
        return {
            'score': obj.score,
            'player_name': obj.player_name
        }

    def create(self, validated_data):
        return HighScore.objects.create(**validated_data)

创建新的基类 (Creating new base classes)

  • 处理将任意对象强制转换为基本表示的通用序列化器
from rest_framework import serializers


class ObjectSerializer(serializers.BaseSerializer):
    """
    任意复杂对象强制转换为原始表示的只读序列化器。
    """
    def to_representation(self, obj):
        for attribute_name in dir(obj):
            attribute = getattr(obj, attribute_name)
            if attribute_name('_'):
                # 忽略私有属性。
                pass
            elif hasattr(attribute, '__call__'):
                # 忽略方法和其他 callables。
                pass
            elif isinstance(attribute, (str, int, bool, float, type(None))):
                # 原始类型可以通过未修改的方式传递。
                output[attribute_name] = attribute
            elif isinstance(attribute, list):
                # 递归处理列表中的项。
                output[attribute_name] = [
                    self.to_representation(item) for item in attribute
                ]
            elif isinstance(attribute, dict):
                # 递归处理字典中的项。
                output[attribute_name] = {
                    str(key): self.to_representation(value)
                    for key, value in attribute.items()
                }
            else:
                # 将其他内容强制到其字符串表示形式。
                output[attribute_name] = str(attribute)

高级序列化器用法 (Advanced serializer usage)

重写序列化和反序列化行为 (Overriding serialization and deserialization behavior)

  • 转换用户名为小写
from rest_framework import serializers


class ObjectSerializer(serializers.BaseSerializer):
	def to_representation(self, instance):
	    """Convert `username` to lowercase."""
	    ret = super().to_representation(instance)
	    ret['username'] = ret['username'].lower()
	    return ret

序列化器继承 (Serializer Inheritance)

from rest_framework.serializers import ModelSerializer


class MyBaseSerializer(ModelSerializer):
    my_field = serializers.CharField()


class MySerializer(MyBaseSerializer):
    my_field = None

动态修改字段 (Dynamically modifying fields)

  • 设置序列化器在初始化时应使用哪些字段
from rest_framework import serializers


class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    ModelSerializer 获取额外的 `fields` 参数来控制哪些字段应该被显示。
    """

    def __init__(self, *args, **kwargs):
        # 不要将 'fields' 参数传递给超类
        fields = kwargs.pop('fields', None)

        # 通常实例化超类
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # 删除`fields`参数中未指定的任何字段。
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值