序列化器,在Django框架终究是一个类,她的作用就是序列化和反序列化
序列化:序列化会把(数据库中的)模型对象转换成字典,经过response以后变成字符串,传给客户端(前端)
[{"name":"西游记","price":"100.00","author":"吴承恩"}]
反序列化:把客户端(前端)送过来的数据,经过request后,变成字典,序列化器可以把字典再转换成模型,最后再存到数据库中
序列化器在反序列化过程中,会自动完成数据校验(数据是否合法,长度是否足够)。
第一步:写一个类:必须继承drf中的Serializer及其子类
第二步:在类中写要序列化的字段(要序列化哪些,就写哪些,不序列化的可以不写)
第三步:在视图类中使用序列化类
第四步:得到序列化类对象(对象.data),通过Response返回给前端
1. 表模型类
class Book(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(decimal_places=2, max_digits=5) author = models.CharField(max_length=32)
2.序列化器
from rest_framework import serializers from .models import Book class BookSerializer(serializers.Serializer): # max_length=32,min_length=3 反序列化保存校验数据的时候用 name = serializers.CharField(max_length=8, min_length=3) price=serializers.CharField() # models中使用了DecimalField,这个位置使用了CharField会把小数类型转成字符串 author = serializers.CharField()
3.视图类
from rest_framework.response import Response from app01.models import Book from rest_framework.views import APIView from app01.serializer import BookSerializer class BookView(APIView): def get(self, request): # 查出来的数据做序列化 book_list = Book.objects.all() # instance:要序列化的对象 qs,单个对象 # many:如果是qs对象,many=True,如果是单个对象many=False ser = BookSerializer(instance=book_list, many=True) # 传入初始化的参数instance=None, data=empty # ser.data使用模型类对象序列化后的字典 return Response(ser.data) # 字典,列表,字符串都行
4.路由
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^books/', views.BookView.as_view()), ]
models中有自己的字段类型
name = models.CharField() price = models.DecimalField()
序列化器中也有自己的字段类型
name = serializers.CharField() price=serializers.CharField()
常用的序列化器字段类型:
CharField IntegerField FloatField DecimalField DateTimeField DateField
字段大全
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol=’both’, unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
models中有自己的字段参数
name = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2)
序列化器中也有自己的字段参数
name = serializers.CharField(max_length=8, min_length=2)
注意
''' read_only:表明该字段仅用于序列化输出,默认False -如果read_only=True,这个字段只用来做序列化---》把对象---》json给前端 write_only:表明该字段仅用于反序列化输入,默认False -如果read_only=write_only,这个字段只用来做反序列化---》前端json---》存到数据库'''
选项参数
参数名称 | 作用 |
---|---|
max_length | 最大长度(CharField) |
min_lenght | 最小长度(CharField) |
allow_blank | 是否允许为空(CharField) |
trim_whitespace | 是否截断空白字符(CharField) |
max_value | 最小值 (IntegerField) |
min_value | 最大值(IntegerField) |
通用参数:
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器(不太用) |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
我们可以通过序列化器自带的方法,自定义我们想要的序列化字段,key(字段名),value(方法返回)都可以定制
比如,作者表和作者详情表(一对一外键关系)
我们可以序列化作者表(作者表里有姓名),并在作者表里自定义作者信息字段
这样我们就可以通过一张表,返回我们想要的(作者,作者信息)序列化数据
from rest_framework import serializers from app01.models import Book class BookSerializer(serializers.Serializer): name = serializers.CharField(max_length=8, min_length=2) price = serializers.CharField() author = serializers.CharField() # 定制序列化字段re_name re_name = serializers.SerializerMethodField() # 必须配合一个方法,方法名get_字段名 def get_re_name(self, obj): # 方法返回什么,字段就是什么,obj是当前序列化到的单个对象 return str(obj.name) + '重置版' # python是动态强类型语言--》强类型是:不同类型之间不允许直接运算 # 定制序列化字段price_info price_info = serializers.SerializerMethodField() def get_price_info(self, obj): return "价格是:" + str(obj.price)
models
class Book(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2) author = models.CharField(max_length=32) @property def re_name(self): return str(self.name) + '重置版' @property def price_info(self): return '价格是' + str(self.price)
serializer
class BookSerializer(serializers.Serializer): name = serializers.CharField(max_length=8, min_length=2) price = serializers.CharField() author = serializers.CharField() # 在models中写方法,这里字段名就是models的方法名,price_info方法返回什么,这个字段就是什么 re_name = serializers.CharField() price_info = serializers.CharField()
authors=serializers.ListField()
authors_info = serializers.DecimalField()
# 第一步:把前端传入的数据,放到Serializer对象中:ser=BookSerializer(data=request.data) # 第二步:校验数据:ser.is_valid(): # 第三步:保存,ser.save()---》必须重写create,在序列化类中 def create(self, validated_data): book = Book.objects.create(**validated_data) return book
视图类
class BookView(APIView): # 反序列化 def post(self, request): # 接收前端返回的数据,使用data参数 ser = BookSerializer(data=request.data) # 校验参数 if ser.is_valid(): # 如果是true表示数据校验通过,通过,就保存 # 如果instance为None,调用save本质会调用create--》父类create直接抛异常,所以我们要重写create ser.save() return Response(ser.data) return Response({'code': 101, 'msg': '数据校验失败', 'err': ser.errors})
序列化器
class BookSerializer(serializers.Serializer): name = serializers.CharField(max_length=8, min_length=2) price = serializers.CharField() author = serializers.CharField() # 定制字段:在models中写方法,这里字段名就是models的方法名,price_info方法返回什么,这个字段就是什么 re_name = serializers.CharField(read_only=True) # 只序列化 price_info = serializers.CharField(read_only=True) # 只序列化 def create(self, validated_data): # validated_data校验过后的数据 # 手动存到book表中 book = Book.objects.create(**validated_data) # book=Book.objects.create(name=validated_data.get('name')) return book # 不要忘记返回book对象
视图类
class BookDetailView(APIView): def get(self, request, pk): book = Book.objects.filter(pk=pk).first() # 查询单条记录 ser = BookSerializer(instance=book) # 如果是单条记录,many不传,就是false return Response(ser.data) def delete(self, request, pk): res = Book.objects.filter(pk=pk).delete() # 删除单条记录 print(res) if res[0] > 0: return Response({'code': 100, 'msg': '删除成功'}) else: return Response({'code': 103, 'msg': '数据不存在'}) def put(self, request, pk): # 修改:用什么数据,修改哪个对象? book = Book.objects.filter(pk=pk).first() # 既有instance,又有data,表示修改 ser = BookSerializer(instance=book, data=request.data) if ser.is_valid(): # 重写update方法 ser.save() # 调用save---》内部根据instance判断是触发create还是update return Response(ser.data) return Response({'code': 102, 'msg': '修改出错', 'err': ser.errors})
序列化类
class BookSerializer(serializers.Serializer): id = serializers.CharField(read_only=True) # max_length=32,min_length=3 反序列化保存校验数据的时候用 name = serializers.CharField(max_length=8, min_length=3) price = serializers.CharField(required=False) # models中使用了DecimalField,这个位置使用了CharField会把小数类型转成字符串 author = serializers.CharField(required=False) def create(self, validated_data): # validated_data校验过后的数据 # 手动存到book表中 book = Book.objects.create(**validated_data) # book=Book.objects.create(name=validated_data.get('name')) return book # 不要忘记返回book对象 def update(self, instance, validated_data): # validated_data校验过后的数据,instance 是要修改的对象 instance.name = validated_data.get('name') instance.price = validated_data.get('price') instance.author = validated_data.get('author') instance.save() # 模型对象自带的save,保存到数据库中 return instance # 不要忘记返回instance对象 # 局部钩子 # 字段有自己的校验:max_length .... ,再校验,就可以写局部钩子 def validate_name(self, attr): # attr就是前端传入的数据 # 名字不能以sb开头 if attr.startswith('sb'): raise ValidationError("名字不能以sb开头") else: return attr # 没有问题,正常返回
路由
urlpatterns = [ path('admin/', admin.site.urls), path('books/', views.BookView.as_view()), path('books/<int:pk>', views.BookDetailView.as_view()), # 用于查询一个,利用转换器<int:pk> ]
虽然序列化器会根据字段参数对字段自动校验,但是某些情况,需要我们主动添加一些校验,这里就要用到局部钩子和全局钩子的概念
from rest_framework.exceptions import ValidationError # 局部钩子 # 字段有自己的校验:max_length .... ,再校验,就可以写局部钩子 def validate_name(self, attr): # attr就是前端传入的数据 # 名字不能以sb开头 if attr.startswith('sb'): raise ValidationError("名字不能以sb开头") else: return attr # 没有问题,正常返回 # 先走字段自己规则,再走局部钩子,再走全局钩子 # 全局钩子 def validate(self, attrs): # attrs校验过后的数据 if attrs.get('name') == attrs.get('author'): raise ValidationError('作者名不能等于书名') else: return attrs
模型类序列化器是与表模型是绑定关系,他通过对序列化器的封装,可以让我们省去重写updata、create
# 以后使用ModelSerializer跟表模型做绑定,以后这个用的多,不需要重写update和create方法了 class BookSerializer2(serializers.ModelSerializer): class Meta: model = Book # 跟那个表有关系,绑定 # fields='__all__' # 这是注册的第一种方式,表示序列化所有字段 fields = ['id', 'name', 'price', 'author', 'price_info'] # 这是注册的第二种方式,序列化自己想要的字段
# id是从表模型中映射过来的,auto,它会不要求你传 # price_info:它不是数据库中字段,使我们扩写的字段 # 注意:即便扩写的字段,也要在fields中注册# 重写字段 # 局部和全局钩子跟之前一样
# 以后使用ModelSerializer跟表模型做绑定,以后这个用的多,不需要重写update和create方法了 class BookSerializer2(serializers.ModelSerializer): class Meta: model = Book # 跟那个表有关系,绑定 # fields='__all__' # 这是注册的第一种方式,表示序列化所有字段 fields = ['id', 'name', 'price', 'author', 'price_info'] # 这是注册的第二种方式,序列化自己想要的字段 # id是从表模型中映射过来的,auto,它会不要求你传 # price_info:它不是数据库中字段,使我们扩写的字段 # 注意:即便扩写的字段,也要在fields中注册 # 原来的字段参数,通过extra_kwargs传进去 extra_kwargs = { 'name': {'write_only': True, 'max_length': 8, 'min_length': 3} } # 重写字段 # 局部和全局钩子跟之前一样,但是要注意写在Meta外
多表模型
from django.db import models class Book(models.Model): name = models.CharField(max_length=32, ) price = models.DecimalField(max_digits=8, decimal_places=2) publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') def __str__(self): return self.name @property def publish_detail(self): return {'name': self.publish.name, 'addr': self.publish.city} @property def author_list(self): l = [] for author in self.authors.all(): l.append({'name': author.name, 'addr': author.author_detail.addr}) return l class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE) class AuthorDetail(models.Model): phone = models.BigIntegerField() birthday = models.DateTimeField() addr = models.CharField(max_length=64) class Publish(models.Model): name = models.CharField(max_length=32, ) city = models.CharField(max_length=32, ) email = models.EmailField(max_length=32, )
序列化器
from app01 import models from rest_framework.serializers import ModelSerializer class BookSerializer(ModelSerializer): class Meta: model = models.Book # fields = '__all__' # depth = 1 fields = ['id', 'name', 'price', 'publish', 'authors', 'publish_detail', 'author_list'] extra_kwargs = { 'publish': {'write_only': True}, 'authors': {'write_only': True} } class AuthorSerializer(ModelSerializer): class Meta: model = models.Author fields = '__all__' class AuthorDetailSerializer(ModelSerializer): class Meta: models = models.AuthorDetail fields = '__all__' class PublishSerializer(ModelSerializer): class Meta(): model = models.Publish fields = '__all__'
视图接口
from rest_framework.response import Response from rest_framework.views import APIView from app01 import models from app01 import serializer class BookView(APIView): def get(self, request): book_list = models.Book.objects.all() ser = serializer.BookSerializer(instance=book_list, many=True) return Response(ser.data) def post(self, request): ser = serializer.BookSerializer(data=request.data) if ser.is_valid(): ser.save() return Response({"code": 100, "msg": "新增成功", "data": ser.data}) return Response({"code": 101, "msg": "新增失败", "err": ser.errors}) class BookDetailView(APIView): def get(self, request, pk): book = models.Book.objects.all().filter(pk=pk).first() ser = serializer.BookSerializer(instance=book) return Response(ser.data) def put(self, request, pk): book = models.Book.objects.all().filter(pk=pk).first() ser = serializer.BookSerializer(instance=book, data=request.data) if ser.is_valid(): ser.save() return Response({"code": 100, "msg": "修改成功", "data": request.data}) return Response({"code": 102, "msg": "修改失败", "err": ser.errors}) def delete(self, request, pk): models.Book.objects.filter(pk=pk).delete() return Response({"code": 100, "msg": "删除成功"})
路由
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('books/', views.BookView.as_view()), path('books/<int:pk>', views.BookDetailView.as_view()), ]
查看所有
添加一个
查看一个
修改一个
删除一个
这里的请求和响应是经过drf封装之后的请求和响应,增加了一些内容
# Request 类的对象---》新的request对象 from rest_framework.request import Request # 记住的 __getattr__ request.data request.query_parmas--->self._request.GET-->restful规范里,请求地址中带过滤(查询)条件---》get请求地址中提交的数据在GET中,---》query_parmas:查询参数 # 了解--->默认情况下,可以解析 urlencoded,formdata,json -如果我们写了一个接口,想只能处理json格式,或者只能处理formdata # 局部配置 from rest_framework.parsers import JSONParser,FormParser,MultiPartParser class PublishView(APIView): # 局部使用,只针对当前视图类有效,只想处理json格式 parser_classes = [JSONParser] # 全局配置---》配置文件--->所有接口都只能解析json格式 REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', ], } # 全局配置解析json,局部某个视图函数想能解析formdata格式 视图类中配置一下即可---》局部配置 -如果局部配置如下,会怎么样 parser_classes = [] # 所有格式都补不能解析了 # 使用顺序:我们没有配置,也有默认配置:3个都能解析 drf有默认配置(最后)----》项目配置文件的配置(其次)----》视图类中配的(优先用) drf的默认配置:from rest_framework import settings # 总结:一般情况下,都使用默认即可,不用配置View Code
Respone:from rest_framework.response import Response # 属性 data=None, # 字符串,字典,列表--》给http响应body体中内容-->response对象中取出处理 status=None, # 响应状态码:1xx,2xx,3xx,默认是200 from rest_framework.status import HTTP_201_CREATED Response(ser.data,status=HTTP_201_CREATED) headers=None, # 响应头 字典 ---了解--- template_name=None, # 模板名字(不用),用浏览器访问时,可以改 exception=False, # 异常处理 content_type=None # 响应编码格式 # 响应格式---》跟解析格式 # 局部设置 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer class BookDetailView(APIView): renderer_classes = [JSONRenderer,] # 全局设置 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类 'rest_framework.renderers.JSONRenderer', # json渲染器 'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器 ) }View Code