Python 学习笔记(十六)--Django REST Framework之serializers
1.序列化组件介绍
序列化:序列化器会把模型对象转换成字典,经过response以后变成json字符串。
反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型。反序列化,可以完成数据校验功能。
2.引入方式
from rest_framework import serializers
3.类的方法和属性
一般 序列化传参instance,反序列化传参data。但是在对既有对象更新时(例如put请求时),此时的发序列化,既要传参instance,也要传参data。
4.序列化类的使用
(1)序列化类,继承 serializers.Serializer (或 serializers.ModelSerializer);
(2)在类中,
为 serializers.Serializer是,明确需要序列化的字段(逐一指明需要的字段);
为 serializers.ModelSerializer,明确 class Meta: 信息。
(3)在视图类中使用:导入序列化类,把要序列化的对象传入, 实例化得到序列化类的对象。【要序列化谁,就把谁传过来,其实就是调用类的__init__,看源码是需注意:这个方法来自父类BaseSerializer】
(4)序列化类的对象.data是一个字典(注意:不是json)。
(5)使用rest_framework.response中的Response,会以Json的形式把字典里面的数据返回。 from rest_framework.response import Response 【如果不使用这个Response,就需要使用JsonResponse (from django.http import JsonResponse)】
5.序列化类的常见字段类型
serializers.CharField()
serializers.IntegerField()
serializers.IntegerField()
serializers.BooleanField()
serializers.ChoiceField()
serializers.JSONField()
7.数据验证(一般用在反序列化)
Serializer中的validate方法:
def validate(self, attrs): return attrs
父类BaseSerializer有个is_valid方法
def is_valid(self, raise_exception=False): assert hasattr(self, 'initial_data'), ( 'Cannot call `.is_valid()` as no `data=` keyword argument was ' 'passed when instantiating the serializer instance.' ) if not hasattr(self, '_validated_data'): try: self._validated_data = self.run_validation(self.initial_data) except ValidationError as exc: self._validated_data = {} self._errors = exc.detail else: self._errors = {} if self._errors and raise_exception: raise ValidationError(self.errors) return not bool(self._errors)
is_valid 返回true 表示验证通过。
注意:不能直接对象.save() , 否则会报错 --NotImplementedError: 'update()' must be implemented。
8.报错原因
Serializer中没有save方法,只是父类BaseSerializer有个save方法.
def save(self, **kwargs): assert hasattr(self, '_errors'), ( 'You must call `.is_valid()` before calling `.save()`.' ) assert not self.errors, ( 'You cannot call `.save()` on a serializer with invalid data.' ) # Guard against incorrect use of `serializer.save(commit=False)` assert 'commit' not in kwargs, ( "'commit' is not a valid keyword argument to the 'save()' method. " "If you need to access data before committing to the database then " "inspect 'serializer.validated_data' instead. " "You can also pass additional keyword arguments to 'save()' if you " "need to set extra attributes on the saved model instance. " "For example: 'serializer.save(owner=request.user)'.'" ) assert not hasattr(self, '_data'), ( "You cannot call `.save()` after accessing `serializer.data`." "If you need to access data before committing to the database then " "inspect 'serializer.validated_data' instead. " ) validated_data = {**self.validated_data, **kwargs} ##注意在反序列化时,一般实例化对象XXXserializer(data=request.data),即self.instance is None(添加对象,不是对既有对象进行编辑).
if self.instance is not None: self.instance = self.update(self.instance, validated_data) assert self.instance is not None, ( '`update()` did not return an object instance.' ) else: self.instance = self.create(validated_data) ###调用对象的create()方法,如果没有定义,就会调用父类的create。create()要有返回值。 assert self.instance is not None, ( '`create()` did not return an object instance.' ) return self.instance
父类BaseSerializer中的create()方法
def create(self, validated_data): raise NotImplementedError('`create()` must be implemented.')
这个create()方法是没有意义的,一定要在子类中重写。另外,需要特别注意的是,重写的create一定要有返回值,没有明确的返回值就会变成了None,后边可能会出现异常(虽然不会报错)。
父类中还有个update()
def update(self, instance, validated_data): raise NotImplementedError('`update()` must be implemented.')
就是这个汇报的错误。
所以,需要在序列化类中,重新这个update方法。重写时,需要注意,instance代表的是序列化类对象,validated_data是校验后的数据。赋值后,不要忘记保存和返回。
即
instance.save() return instance
9. 有必要看下父类BaseSerializer的代码,特别是__init__,需要留意的是data参数。
在视图类中,一般通过 序列化类(instance=model的对象, data=request.data),这种格式进行反序列化。
class BaseSerializer(Field): """ The BaseSerializer class provides a minimal class which may be used for writing custom serializer implementations. Note that we strongly restrict the ordering of operations/properties that may be used on the serializer in order to enforce correct usage. In particular, if a `data=` argument is passed then: .is_valid() - Available. .initial_data - Available. .validated_data - Only available after calling `is_valid()` .errors - Only available after calling `is_valid()` .data - Only available after calling `is_valid()` If a `data=` argument is not passed then: .is_valid() - Not available. .initial_data - Not available. .validated_data - Not available. .errors - Not available. .data - Available. """ def __init__(self, instance=None, data=empty, **kwargs): self.instance = instance if data is not empty: self.initial_data = data self.partial = kwargs.pop('partial', False) self._context = kwargs.pop('context', {}) kwargs.pop('many', None) super().__init__(**kwargs)
10. 通过 钩子函数 丰富验证
局部钩子
通过 validate_字段名(self,接受一个参数), 定义一个钩子函数,丰富对字段的验证。
全局钩子
就是重写serializers.Serializer 中的 validate 方法
def validate(self, attrs): return attrs
11.举例(重新update+钩子函数)
class UserDetailSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): for attr, value in validated_data.items(): if attr == "password": instance.set_password(value) elif attr in ("groups", "user_permissions", "resource_group"): getattr(instance, attr).set(value) else: setattr(instance, attr, value) instance.save() return instance def validate_password(self, password): try: validate_password(password) except ValidationError as msg: raise serializers.ValidationError(msg) return password class Meta: model = Users fields = "__all__" extra_kwargs = { "password": {"write_only": True, "required": False}, "username": {"required": False}, }
例子来自:https://gitee.com/rtttte/Archery/blob/master/sql_api/serializers.py
12 serializers.CharField(read_only=True)
read_only=True: 表明该字段仅用于序列化输出,默认为False。如果设置为True,get方式可以看到该字段;而修改时(例如put方式),不需要传该字段。
write_only=True:表明该字段仅用于反序列化,默认为False。如果设置为True,get方式看不到该字段;而修改时(例如put方式),需要传该字段。
还有些其它属性
source:序列化类中的字段名字对应的是模型层下表名内对应的字段名,但有的时候我们需要确保数据的安全,并不想直接将真实的字段名返回给前端用户查看,这个时候我们就可以利用source参数来将返回给前端的字段名进行修改;
required :表明该字段在反序列化时必须输入,默认为True;
default: 发序列化时使用的默认值;
allow_null: 表明该字段是否允许传入None,默认False;
validators :该字段使用的验证器;
error_messages:包含错误编号与错误信息的字典;
label:用于HTML展示API页面时,显示的字段名称;
help_text:用于HTML展示API页面时,显示的字段帮助提示信息.
13模型类序列化器--serializers.ModelSerializer
它可让基于 Models
自动创建一个 Serializer
类,其中的字段与模型类字段对应。并且它包含 create()
和 update()
的简单默认实现。
举例
class QueryPrivilegesApplySerializer(serializers.ModelSerializer): class Meta: model = QueryPrivilegesApply ##对应models.py 中的指定模型 fields = "__all__" ## 指定序列化的字段; "__all__" 所有字段;或者通过("id", "rds_dbinstanceid", "is_enable", ...) 指定想要的字段.
exclude = [xxx,xxx] ## 明确指明排除的字段,注意:fields 和 exclude 属性,在模型类序列化器中只能同时用一个.
read_only_fields ## 指明只读字段;write_only_fields 这个属性被淘汰掉了,后面要通过extra_kwargs属性实现.
extra_kwargs = {"某字段": {"write_only": True}, "某字段": {"required": True}} ##添加或者修改原有的选项参数
14 ModelSerializer 的基本功能和常用方法属性
概说
class ModelSerializer(Serializer): """ A `ModelSerializer` is just a regular `Serializer`, except that: * A set of default fields are automatically populated. * A set of default validators are automatically populated. * Default `.create()` and `.update()` implementations are provided. The process of automatically determining a set of serializer fields based on the model fields is reasonably complex, but you almost certainly don't need to dig into the implementation. If the `ModelSerializer` class *doesn't* generate the set of fields that you need you should either declare the extra/differing fields explicitly on the serializer class, or simply use a `Serializer` class. """
常用方法和属性
15 序列化的对象是多行数据还是单行数据
序列化的对象是多行数据时,参数中一定要有many=True, 这个控制了序列化后对象的类型.
回顾下: Python对象的生成
step 1 对象生成 ----先调用类的__new__方法,生成空对象;类的__new__方法控制对象的生成.
step 2 对象实例化----- 即 对象=类名(XXXX),触发类的__init__() 方法.
我们回头再看序列化.
序列化对象生成,依赖于 BaseSerializer 类的 __new__ 方法
具体代码
def __new__(cls, *args, **kwargs): # We override this method in order to automatically create # `ListSerializer` classes instead when `many=True` is set. if kwargs.pop('many', False): ###默认时False, 不传的化,就是False return cls.many_init(*args, **kwargs) ###通过类的绑定方法,这种方式实现
###如果没有传many=True,执行下面代码,正常的对象实例化 return super().__new__(cls, *args, **kwargs)
调用的代码
@classmethod def many_init(cls, *args, **kwargs): """ This method implements the creation of a `ListSerializer` parent class when `many=True` is used. You can customize it if you need to control which keyword arguments are passed to the parent, and which are passed to the child. Note that we're over-cautious in passing most arguments to both parent and child classes in order to try to cover the general case. If you're overriding this method you'll probably want something much simpler, eg: @classmethod def many_init(cls, *args, **kwargs): kwargs['child'] = cls() return CustomListSerializer(*args, **kwargs) """ allow_empty = kwargs.pop('allow_empty', None) max_length = kwargs.pop('max_length', None) min_length = kwargs.pop('min_length', None) child_serializer = cls(*args, **kwargs) list_kwargs = { 'child': child_serializer, } if allow_empty is not None: list_kwargs['allow_empty'] = allow_empty if max_length is not None: list_kwargs['max_length'] = max_length if min_length is not None: list_kwargs['min_length'] = min_length list_kwargs.update({ key: value for key, value in kwargs.items() if key in LIST_SERIALIZER_KWARGS }) meta = getattr(cls, 'Meta', None) list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer) return list_serializer_class(*args, **list_kwargs)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库