Django-restframework17 Serializer

2023-10-20 07:32

本文主要是介绍Django-restframework17 Serializer,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    • Serializers
      • 简介
      • 使用示例
        • 创建一个对象
        • 声明一个serializer类提供序列化和反序列化方法
        • 序列化对象转化为python的原生数据类型再转化为其他格式
        • 反序列化对象首先将数据流转化为python原生数据
        • 保存实例
        • 验证
        • 访问初始数据和实例
        • 部分更新
        • 处理嵌套对象
        • 处理多个对象
        • 包含额外的上下文
    • ModelSerializer
      • 1指定包含的字段
      • 2指定显示嵌套对象的显示深度
      • 3明确的指出字段
      • 4指定只读字段
      • 附加的关键字参数
      • 相关字段
      • 自定义字段映射
        • 字段类和字段参数
    • HyperlinkedModelSerializer
      • 绝对和相对url
      • 如何决定合适的hyperlinked函数
      • 改变url字段名
    • ListSerializer
      • 定制ListSerializer行为
      • 定制多个对象创建方法
      • 定制多个对象更新方法
      • 定制ListSerializer初始化内容
    • BaseSerializer
      • 基本介绍
      • 创建一个读写的序列化类
      • 创建一个新的基础类BaseSerializer
    • 序列化类的高级用法
      • 重写序列化方法和反序列化方法
      • 继承序列化器
      • 动态的修改字段
      • 自定义默认字段
    • 第三方模块

1 Serializers

1 简介

序列化器允许将诸如queryset和模型实例之类的复杂数据转换为原生的Python数据类型,这些数据类型可以很容易地转换为JSON、XML或其他内容类型。序列化器还提供反序列化,允许解析后的数据在第一次验证传入数据之后被转换回复杂类型。
REST框架中的序列化器与Django的表单和模型类的工作非常相似。框架提供了一个Serializer类,使用一种强大的、通用的方法来控制响应的输出,和一个ModelSerializer类,它为创建处理模型实例和queryset的序列化器提供了一个有用的快捷方式。

2 使用示例

1.创建一个对象
from datetime import datetimeclass Comment(object):def __init__(self, email, content, created=None):self.email = emailself.content = contentself.created = created or datetime.now()comment = Comment(email='leila@example.com', content='foo bar')
2. 声明一个serializer类,提供序列化和反序列化方法
from rest_framework import serializers

class CommentSerializer(serializers.Serializer):email = serializers.EmailField()content = serializers.CharField(max_length=200)created = serializers.DateTimeField()
3. 序列化对象(转化为python的原生数据类型,再转化为其他格式)
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 JSONRendererjson = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
4. 反序列化对象(首先将数据流转化为python原生数据)
from django.utils.six import BytesIO
from rest_framework.parsers import JSONParser# 转化成数据流
stream = BytesIO(json)
# 使用json解析器转化成python原生数据类型,从字符串中解析出json对象
data = JSONParser().parse(stream)
# 将这些原生数据恢复到验证字典中
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
5. 保存实例

如果我们想返回一个完整的对爱实例,那么我们必须基于validated data实现一个.create()或update()方法,或者两个都实现

class CommentSerializer(serializers.Serializer):email = serializers.EmailField()content = serializers.CharField(max_length=200)created = serializers.DateTimeField()def create(self, 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)return instance

如果对象与数据模型一致,也想保存对象到数据库模型中:

def create(self, validated_data):# 使用数据库模型对象进行创建return Comment.objects.create(**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

最后我们对通过验证的对象进行保存

comment = serializer.save()

.save()方法到底是更新还是创建,取决于我们是否传入一个已经存在的序列化实例,如:

# .save()将会创建一个新的实例
serializer = CommentSerializer(data=data)# .save()将会更新已经存在的comment实例
serializer = CommentSerializer(comment, data=data)

保存时添加附加属性
有时,您希望您的视图代码能够在保存实例的时候注入额外的数据。这些额外的数据可能包括当前用户、当前时间或其他不属于请求数据的信息。

serializer.save(owner=request.user)

添加的附加信息也会被包含在validated_data中,然后传入到.create()或update()函数中去
重写保存方法
有时created()和update()方法名字命名不能传达出实际意义,就需要重写,如下, 你应该重写方法:

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)
6.验证

在反序列化数据时,在获取validated_data或保存实例前需要调用is_valid()方法,如果验证时发生了错误,serializer.errors将会包含发生的错误信息:

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.']}

错误字典中的每一个键都应该是字段名,non_field_errors也会列出具体的字段信息,可以通过
框架设置NON_FIELD_ERRORS_KEY来设置non_field_errors的字段名。
对于验证不合法的数据也可以抛出异常,设置raise_exception=True.

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

单个字段验证
添加.validate_方法(类似.clean_方法),如

from rest_framework import serializers# 博客提交时的标题必须含有‘django’
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

如果字段设置了required=False,而且提交的时候没有包含这个字段,那么就不会被验证
如果需要对多个字段的值进行比较验证,应该重写.validate()方法,返回validated values或抛出ValidationError。

from rest_framework import serializersclass 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

序列化上的每个字段都可以包含验证器:

def multiple_of_ten(value):if value % 10 != 0:raise serializers.ValidationError('Not a multiple of ten')class GameRecord(serializers.Serializer):score = IntegerField(validators=[multiple_of_ten])...

可重用的验证类,在元类中声明:

class EventSerializer(serializers.Serializer):name = serializers.CharField()room_number = serializers.IntegerField(choices=[101, 102, 103, 201])date = serializers.DateField()class Meta:# 每天每间房只能干一件事validators = UniqueTogetherValidator(queryset=Event.objects.all(),fields=['room_number', 'date'])
7. 访问初始数据和实例

当将初始对象或queryset传递给序列化器实例时,对象将被作为.instance调用。如果没有初始对象被传递,那么.instance的值将为None。
当将数据传递给序列化器实例时,未修改的数据将被作为.initial_data提供。如果没有传递,那么initial_data属性将不存在。

8. 部分更新

默认需要传入全部字段,否则会产生错误,可以利用partial参数,只传入需要更新的字段

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
9. 处理嵌套对象

serializer本身也是一个字段类型field,可以作为其他序列化类中的字段类型,如

class UserSerializer(serializers.Serializer):email = serializers.EmailField()username = serializers.CharField(max_length=100)class CommentSerializer(serializers.Serializer):# 使用了其他序列化器,来形成嵌套,如果允许为空,接受None值,应该设置required=False#  user = UserSerializer(required=False) 即允许匿名对象评论user = UserSerializer()# 如果传入的序列化器是一系列对象,应该设置many=Trueedits = EditItemSerializer(many=True)content = serializers.CharField(max_length=200)created = serializers.DateTimeField()

使用示例:

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()方法

class UserSerializer(serializers.ModelSerializer):profile = ProfileSerializer()class Meta:model = Userfields = ('username', 'email', 'profile')def create(self, validated_data):# pop方法使用最后传入的数据profile_data = validated_data.pop('profile')user = User.objects.create(**validated_data)Profile.objects.create(user=user, **profile_data)return user

编写一个update方法,需要对所有类进行更新,首先获取原对象,然后根据是否传入新的数据更新对象。如果相关数据为None或者没有提供,如何进行处理:
- 设置相关对象值为Null
- 删除相关实例
- 无视数据,保持原数据
- 抛出一个错误

    def update(self, instance, validated_data):profile_data = validated_data.pop('profile')# 除非应用强制此字段必须被设置,接下来可能会抛出需要处理`DoesNotExist’的异常# 获取原来的profile实例profile = instance.profile# 获取新的信息,如果不存在就使用以前的信息instance.username = validated_data.get('username', instance.username)instance.email = validated_data.get('email', instance.email)instance.save()# profile是否是优质成员,profile属性profile.is_premium_member = profile_data.get('is_premium_member',profile.is_premium_member)# profile是否支持协议,profile属性profile.has_support_contract = profile_data.get('has_support_contract',profile.has_support_contract)profile.save()return instance

由于嵌套的对象的更新和创建有着复杂的依赖关系,所以REST3要求用户自己编写嵌套列表的更新和创建操作,默认不再包含。
也有第三方包提供自动创建一些自动更新和创建嵌套对象的操作
在模型管理器中处理保存操作
在序列化类中处理多个相关实例的方法是编写个性化的模型管理类来处理创建操作,例如:

class UserManager(models.Manager):...# 确保了user实例和profiles实例是同时创建的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
# 然后序列化类中的创建方法也可以重写为
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'])
10. 处理多个对象

Serializer也可以处理多个对象
- 序列化多个对象
设置many=True就可以

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'}
# ]

-反序列化多个对象
默认支持多个对象创建,但不支持多个对象同时更新。若需要支持多个对象同时更新,需要自定义

11. 包含额外的上下文

有时你需要提供额外的上下文使对象能够被正确的序列化。比如你准备序列化一个包含一个超链接事务,你需要序列化类能够使用目前的request对象来生成合格的url.

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'}

上下文字典可以使用在任何序列化字段中,例如可以自定义一个.to_representation()方法,查看self.context属性

3 ModelSerializer

你通常会想定义一个与数据库模型密切相关的序列化类。 ModelSerializer类提供了一个快捷方式,使你能够自动创建一个字段与模型一致的序列化类。
ModelSerializer与Serializer的区别:
- 自动基于数据库模型生成一系列字段
- 自动为序列化类生成验证函数,例如唯一性验证
- 包含简单的.create()和.update(),嵌套的需要自己编写

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

默认情况下,类中所有字段都与模型一致,模型中的foreignkey,在序列化类中将会变成PrimaryKeyRelatedField。反向关系在默认情况下是不包含的,除非你在 serializer关系文档中明确声明了。
检查ModelSerializer
可以查看ModelSerializers到底为你创建了哪些字段以及详细内容

>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():id = IntegerField(label='ID', read_only=True)name = CharField(allow_blank=True, max_length=100, required=False)owner = PrimaryKeyRelatedField(queryset=User.objects.all())

1指定包含的字段

使用modelSerializer时,如果想仅包含部分字段,可以通过设置fields或者exclude属性。强烈建议显示的设置需要显示的所有字段,这样模型改变时,就不会无意间暴露数据。例如:

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

你也可以将fields属性设置为’all‘,不过不推荐。exclude:不显示谁。

2指定显示嵌套对象的显示深度

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

3明确的指出字段

可以添加额外的字段,或者重写默认的字段,额外的字段应该与模型字段一致,或者能够在模型中调用

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

4指定只读字段

你可能想将多个字段同时指定为只读属性,而不是一个个添加read_only=True属性,你可以使用meta中的可选项:read_only_fields.

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

模型字段中如果设置为AutoField和editable=False,将被自动设置为只读
有一个特殊的具有只读属性的例子是unique_together,它要求序列化类对其进行验证,但又不能被用户编辑。正确处理方式,是给字段设置属性read_only=True和default=…,例如

user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())

5. 附加的关键字参数

extra_kwargs参数能够为一个字段快捷的提供多个附加参数,这样就不用在fields字段中声明

class CreateUserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ('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

6. 相关字段

在序列化模型实例时,有多种方式用来表现关系,ModelSerializer默认采用主键来关联相关对象。
另外一种方式是利用超链接序列化,嵌套序列化和其他自定义的序列化方式。

7. 自定义字段映射

ModelSerializer类也暴露了一个API用于重写,以查看序列化类是怎么自动创建字段的
如果ModelSerializer没有默认创建你说期望的字段,你可以在类中显示的声明它们,或者创建一个基类,用于定义序列化类如何根据模型创建自动创建字段。
- .serializer_field_mapping
- .serializer_related_field(表示关系字段)
ModelSerializer默认为PrimaryKeyRelatedField
HyperlinkedModelSerializer默认为serializers.HyperlinkedRelatedField
- serializer_url_field(url)
- serializer_choice_field(choice)

字段类和字段参数
  • .build_standard_field(self, field_name, model_field)
  • .build_relational_field(self, field_name, relation_info)
    relation_info为一元组,包含model_field, related_model, to_many和 has_through_model
  • .build_nested_field(self, field_name, relation_info, nested_depth)
    匹配模型中的关系型字段
  • .build_property_field(self, field_name, model_class)
  • .build_url_field(self, field_name, model_class)
  • .build_unknown_field(self, field_name, model_class)

4 HyperlinkedModelSerializer

HyperlinkedModelSerializer与ModelSerializer是十分类似的,除了用hyperlinks来代替PK呈现关系。该类默认包含一个url字段用来代替pk字段。url属于HyperlinkedIdentityField字段,该模型中的所有关系都会由HyperlinkedIdentityField链接,你也可以显示的包含此字段

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

1. 绝对和相对url

当初始化HyperlinkedModelSerializer时,必须请求上下文中包含当前request使生成的url包含主机名,为绝对路径,而不是相对路径

serializer = AccountSerializer(queryset, context={'request': request})
absolute:http://api.example.com/accounts/1/
relative:/accounts/1/

如果想获得相对路径时,需要将contex设置为{‘request’: None}

2. 如何决定合适的hyperlinked函数

默认的超链接应该与’{model_name}-detail’模式一致,然后通过pk查询,也可以通过extra_kwargs设置view_name和lookup_field,重写url的字段名和查询参数名:

class AccountSerializer(serializers.HyperlinkedModelSerializer):class Meta:model = Accountfields = ('account_url', 'account_name', 'users', 'created')extra_kwargs = {'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},'users': {'lookup_field': 'username'}}

或者可以在serializer类中明确的设置

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 = Accountfields = ('url', 'account_name', 'users', 'created')

通过打印repr(HyperlinkedModelSerializer)实例能够明确显示view_name和lookup_field

3. 改变url字段名

默认为‘url’, 也可以全局设置URL_FIELD_NAME

5. ListSerializer

ListSerializer能够同时查询或序列化多个对象。不过一般都不直接使用ListSerializer,而是通过设置
many=True参数。
当你为序列化器设置many=True时, 就创建了一个 ListSerializer。
ListSerializer当设置allow_empty为True则允许空值作为合法返回值,False则不允许

1. 定制ListSerializer行为

  1. 有时候你想使用特殊的验证,例如检查列表中一个元素是否与另外的元素存在冲突
  2. 为多个对象定制创建和更新方法
    可以在serializers.Serializer中使用many=True,另外Meta中设置 list_serializer_class选项
class CustomListSerializer(serializers.ListSerializer):...class CustomSerializer(serializers.Serializer):...class Meta:list_serializer_class = CustomListSerializer

2. 定制多个对象创建方法

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

3. 定制多个对象更新方法

ListSerializer默认不支持多个对象同时更新。因为这个行为到底是应该进行插入还是删除是模糊不清的。
为了支持多对象更新,你应该写的十分明确
- 怎样确定数据列表中的哪几个应该被更新?
- 插入操作怎么处理,插入数据是否合法?还是创建一个新的对象?
- 移除操作怎么处理是移除对象还是移除关系?它们应该被忽略还是不合法?
- 排序操作怎么处理?改变两个元素的位置还是忽略它们?
你需要显示的添加id字段到显示中去,默认创建的id字段是只读的,这将导致其无法更新。一旦你显示声明了,那他就会被update操作所更新。

# 处理多个对象的方法
class BookListSerializer(serializers.ListSerializer):def update(self, instance, validated_data):# 利用id将原数据book对象和需要更新的数据对象链接起来# 获取原来数据的id,生成了一个字典对象id-instancebook_mapping = {book.id: book for book in instance}# 获取更新对象的iddata_mapping = {item['id']: item for item in validated_data}# 重写创建和更新方法ret = []# 获取更新对象的id和实际对象for book_id, data in data_mapping.items():# 在原有数据中查找是否存在该id为book_id的对象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()# 所以ret为更新后的对象和新建的对象(book)return retclass BookSerializer(serializers.Serializer):# 我们需要利用主键鉴别这个元素,所以我们需要显示的指定可读写的id,而不是使用默认只读的id.id = serializers.IntegerField()...id = serializers.IntegerField(required=False)class Meta:# 更新多个对象的时候就会调用这个类list_serializer_class = BookListSerializer

3.1版本的REST框架自动创建了多对象同时更新的方法,类似于REST 2中提供的allow_add_remove行为

4. 定制ListSerializer初始化内容

当serializer设置many=True时,子类Serializer和父类ListSerializer的init()方法都应该确认接收哪些参数和关键字参数。
默认将所有的参数传递给两个类,除了validators和任何自定义的关键字参数,这两个参数是默认由子类处理的。
当many= True时,如果你需要定义这两个类是如何进行初始化的,你可以利用many_init这个类方法。

@classmethod
def many_init(cls, *args, **kwargs):# 初始化子类序列器kwargs['child'] = cls()# 初始化父类list序列器return CustomListSerializer(*args, **kwargs)

5 BaseSerializer

1.基本介绍

BaseSerializer轻松支持可选的序列化样式和反序列化样式
BaseSerializer和Serializer一样实现简单的API
- data:返回输出的原始表示
- is_valid():反序列化并验证数据是否合法
- validated_data:验证成功后返回的数据
- errors: 验证失败后产生的错误
- save():保存数据到对象实例中
- .to_representation():重写此方法以支持序列化,用于进行读操作
- .to_internal_value():重写此方法以支持反序列化,进行写操作
- .create()和.update():重写这两个方法,以支持保存实例
因为BaseSerializer提供了和Serializer一样的接口,所以你可以像使用Serializer或者ModelSerializer一样使用存在的基本的类视图函数
唯一的不同之处就是BaseSerializer不会产生可供浏览器使用的API,这是因为他不会返回全部字段信息,允许每一个字段都以合适的方式进行渲染
利用BaseSerializer实现一个只读的序列化类,只需要重写.to_representation()方法就行

# 创建一个数据库模型
class HighScore(models.Model):created = models.DateTimeField(auto_now_add=True)player_name = models.CharField(max_length=10)score = models.IntegerField()# 通过将HighScore转换成简单的原始数据类型。
class HighScoreSerializer(serializers.BaseSerializer):def to_representation(self, obj):return {'score': obj.score,'player_name': obj.player_name}# 现在我们就可以使用HighScoreSerializer序列化单个或多个HighScore实例了
@api_view(['GET'])
def high_score(request, pk):instance = HighScore.objects.get(pk=pk)serializer = HighScoreSerializer(instance)return Response(serializer.data)@api_view(['GET'])
def all_high_scores(request):queryset = HighScore.objects.order_by('-score')serializer = HighScoreSerializer(queryset, many=True)return Response(serializer.data)

2. 创建一个读写的序列化类

  • 首先,我们需要实现to_internal_value()方法,该方法返回验证后的数据用来构成对象实例,如果数据格式不对会抛出ValidationError。
  • 一旦实现了to_internal_value()方法,基础的验证接口就可以使用了,如 .is_valid(), .validated_data和.errors
  • 如果需要支持.save()方法,需要实现.create()和.update()中至少一种。
class HighScoreSerializer(serializers.BaseSerializer):# 读写操作基础def to_internal_value(self, data):score = data.get('score')player_name = data.get('player_name')# 数据验证if not score:raise ValidationError({'score': 'This field is required.'})if not player_name:raise ValidationError({'player_name': 'This field is required.'})if len(player_name) > 10:raise 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)

3. 创建一个新的基础类(BaseSerializer)

应用场景:实现一个通用的类用来处理特殊的序列化风格,或者集成可插拔的后端

# 将任何对象转化成原始数据
class ObjectSerializer(serializers.BaseSerializer):"""将复杂对象转化成简单的只读原始数据"""def to_representation(self, obj):# 列出对象的所有属性和方法for attribute_name in dir(obj):attribute = getattr(obj, attribute_name)if attribute_name('_'):# 属性名中含有_的为私有属性,无视passelif hasattr(attribute, '__call__'):# 无视方法和可以当函数调用的passelif isinstance(attribute, (str, int, bool, float, type(None))):# 输出数据类型为原始数据类型的output[attribute_name] = attributeelif 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)

6 序列化类的高级用法

1. 重写序列化方法和反序列化方法

如果你需要修改序列化、反序列化或验证数据的方法,你可以重写.to_representation()或者 .to_internal_value()
应用场景:
- 为基础类添加一个新的方法
- 轻微修改存在类的方法
- 提高需要频繁访问返回大量数据的接口的序列化性能
特征方法:
- .to_representation(self, obj):一般返回python内置的数据类型结构,具体类型通过render_classes指定
- .to_internal_value(self, data):数据验证返回validated_data,如果序列化类中调用了save方法,那么validated_data就会被.create()或.update()所接收,验证错误就会抛出ValidationError(errors)。接收的data一般为request.data的值,所以接收的数据类型为通过API指定的Parser类型

2. 继承序列化器

和django中的表单类似,你可以通过继承,重用序列化类。意味着可以在一个父类中声明常用的字段和方法,然后给多个类使用

class MyBaseSerializer(Serializer):my_field = serializers.CharField()# 验证单个字段的方法 (validate_{fieldname})def validate_my_field(self):...class MySerializer(MyBaseSerializer):...

和django的Model,ModelForm类似,序列化器内部Meta类并不会隐式的继承父类的Meta,如果需要继承父类的Meta类,应该显示指明

class AccountSerializer(MyBaseSerializer):class Meta(MyBaseSerializer.Meta):model = Account

一般我们不推荐使用元类继承,而是在元类中明确的声明它们,另外在使用序列化类继承时有以下几点需要注意:
- 如果多个基类中声明了同一个Meta类,那么只有第一个会被使用,如果没有,那么就是第一个父类的Meta.
- 子类可以将父类中的字段设置为None来达到删除父类字段的目的,还有另外一种方法

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

3. 动态的修改字段

当序列化器完成初始化之后,字段(fields)字典就可以使用.fields属性直接访问。这就使你可以动态的修改fields属性
这样就可以在程序运行时修改字段而不需要在序列化器中声明

class DynamicFieldsModelSerializer(serializers.ModelSerializer):"""传入了fields属性,就可以动态的指定显示字段"""def __init__(self, *args, **kwargs):# 不给父类传递任何字段fields = kwargs.pop('fields', None)# 正常的初始化父类super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)# 如果没有在参数中指定fields,就返回院本指定的全部字段if fields is not None:# 删除没有在初始化时传入fields参数中声明的参数# 允许的,指定的fields参数allowed = set(fields)# 存在的参数existing = set(self.fields.keys())# 列表减法for field_name in existing - allowed:self.fields.pop(field_name)# 使用实例
>>> class UserSerializer(DynamicFieldsModelSerializer):
>>>     class Meta:
>>>         model = User
>>>         fields = ('id', 'username', 'email')
>>>
>>> print UserSerializer(user)
{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}
>>>
>>> print UserSerializer(user, fields=('id', 'email'))
{'id': 2, 'email': 'jon@example.com'}

4 自定义默认字段

REST2中提供了一个接口允许开发者重写ModelSerializer自动生成默认字段的过程。
接口包括.get_field(), .get_pk_field()和其他方法
REST3中已经移除了这个接口,就不要想太多。如果实在要修改,就需要引用源码。

7 第三方模块

  1. Django REST marshmallow
    django-rest-marshmallow,使用marshmallow,可以替代serializer,简易替换器
  2. Serpy
    serpy ,用于提升序列化速度的,将复杂数据类型序列化为简单的原生类型。
  3. MongoengineModelSerializer
    django-rest-framework-mongoengine,提供了一个MongoEngineModelSerializer,支持使用MongoDB作为存储层
  4. GeoFeatureModelSerializer
    django-rest-framework-gis, 支持对GeoJSON的读写操作
  5. HStoreSerializer
    django-rest-framework-hstore ,提供HStoreSerializer,支持django-hstore的DictionaryField模型字段和schema-mode特性。
  6. Dynamic REST
    dynamic-rest,继承了ModelSerializer和ModelViewSet接口,添加了API查询参数,用于 filtering, sorting, including / excluding和关系
  7. DRF FlexFields
    rf-dynamic-fields包提供了一个mixin,可以动态地将每个序列化器的字段限制为一个URL参数指定的子集。
  8. Serializer Extensions
    drf-flex-fields包扩展了ModelSerializer和ModelViewSet,提供了用于动态设置字段和将原始字段扩展到嵌套模型的常用功能,从URL参数和序列化器类中定义。
  9. HTML JSON Forms
    html-json-forms包
  10. DRF-Base64
    drf-base64提供一组字段和模型序列化器,用于处理base64编码文件的上传
  11. QueryFields
    djangorestframework-queryfields允许API客户端通过 inclusion/exclusion查询参数指定将在响应中发送哪些字段。
  12. DRF Writable Nested
    drf-writable-nested包提供可写的嵌套模型序列化器,它允许使用嵌套相关数据create/update模型。

这篇关于Django-restframework17 Serializer的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/245641

相关文章

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

利用Django框架快速构建Web应用:从零到上线

随着互联网的发展,Web应用的需求日益增长,而Django作为一个高级的Python Web框架,以其强大的功能和灵活的架构,成为了众多开发者的选择。本文将指导你如何从零开始使用Django框架构建一个简单的Web应用,并将其部署到线上,让世界看到你的作品。 Django简介 Django是由Adrian Holovaty和Simon Willison于2005年开发的一个开源框架,旨在简

Linux搭建Python3、Django环境

开发十年,就只剩下这套架构体系了! >>>    好久没写了,朋友们,我又回来了。 安装Python3 Python全部版本下载地址:         https://www.python.org/ftp/ 解决RedHat,使用Python3退格出现乱码问题:         yum -y install readline-devel.x86_64 下载Python3:

Django 第十七课 -- 视图 - FBV 与 CBV

目录 一. 前言 二. FBV 三. CBV 一. 前言 FBV(function base views) 基于函数的视图,就是在视图里使用函数处理请求。 CBV(class base views) 基于类的视图,就是在视图里使用类处理请求。 二. FBV 基于函数的视图其实我们前面章节一直在使用,就是使用了函数来处理用户的请求,查看以下实例: 路由配置: urlpat

django摄影竞赛小程序论文源码调试讲解

2系统关键技术及工具简介 系统开发过程中设计的关键技术是系统的核心,而开发工具则会影响的项目开发的进程和效率。第二部分便描述了系统的设计与实现等相关开发工具。 2.1 Python简介 Python 属于一个高层次的脚本语言,以解释性,编译性,互动性和面向对象相结合。在设计上相比其他语言,它更具有特色语法结构,很强的可读性。 2.2 Django框架 Django是一个开放源

Django 测试指南

#Django 测试指南 对绝大部分人来说,测试Django应用感觉很神秘,他们只是听说代码必须要测试,但是经常找不到线索如何入手。当他们看了Django的测试文档,他们找到深入的哪些功能是可用的,但是如果实现没有任何指导。 这是本博客系列的第一篇,尝试帮助大家减轻压力,使得每个人在测试潮流。假设你从来没有做过任何测试,但是对Python&Django很熟悉了。 我们将贯穿添加测试到pere

使用django-simple-captcha遇到的坑

使用django-simple-captcha遇到的坑 一站点gongshare.com在做注册功能时验证码采用的django-simple-captcha,因为笔者开发环境采用的Windows 64bit系统,结果安装使用的时候接二连三遇到好几个坑。 django-simple-captcha需要依赖django1.3+、PIL1.1.7+或者Pillow2.0+,根据文档安装后开始使用时,

解决Django会话中的竞态条件

Django 会话中的竞态条件(race condition)问题通常发生在多个请求几乎同时修改同一个会话数据时,导致数据丢失或数据不一致。这种情况在需要频繁更新会话数据的场景(如实时聊天应用、并发请求处理等)中尤为常见。 1、问题背景 在 Django 中使用会话时,可能会遇到竞态条件,导致数据丢失或不一致。竞态条件是指两个或多个请求同时访问共享资源时,由于执行顺序的不确定性,导致数据不

Django+Vue3前后端分离学习(五)(前端登录页面搭建)

1、如果需要使用组合式API,需要安装插件: npm install vite-plugin-vue-setup-extend --save-dev 在vite.config.js里配置: 首先导入: import VueSetupExtend from 'vite-plugin-vue-setup-extend' 添加: 2、创建login.vue 然后再index.js里添加

Python——在Linux和Windows下创建Django项目

前言:我和一个室友合作写了一个网站,“网络数据库技术”的课程 project。 从2016年4月8日开始,到2016年4月29日发布第一个版本,在这三个星期的时间里面,前一半时间用来学习Python,Django和Git/GitHub,后一半时间现学现卖,真正在写网站。期间充满了对于未知的探索,在短时间内增加了很多新技能,对整个互联网有了更深的认识。 这个 web project 发布在G