day72:drf:
目录
5.Field字段参数:read_only和write_only
1.续:反序列化功能(5-8)
用户post类型提交数据,反序列化功能的步骤
class Student(View):
def get(self,request):
... def post(self,request):
'''1.获取用户在前端输入的数据'''
recv_data = {
'name':request.POST.get('name'),
'age':request.POST.get('age'),
'class_null':request.POST.get('class_null'),
'description':request.POST.get('description'),
}
'''2.实例化序列化器类,生成序列化器类对象,并将我们获取的数据传进去完成对数据的反序列化'''
ser = StudentSerizlizer(data=recv_data) '''3.校验,全部通过得到True,一个字段错了都是得到False'''
print(ser.is_valid()) '''4.所有字段的错误信息'''
print(ser.errors) '''---------------------------------------------------------------''' '''5.反序列化完成之后的数据'''
print(ser.validated_data) '''6.将反序列化后的数据添加到数据库中'''
ret = models.Student.objects.create(
**ser.validated_data
) '''7.反序列化的数据已经存储到数据库中,但是现在需要前端显示出我们新添加的数据'''
'''按照接口规范:如果post请求提交保存了一条记录,那么要将新添加的数据再响应回去'''
serializer = StudentSerializer(instance=ret)
print(serializer.data) # 序列化完成后的数据 '''8.将序列化完成后的数据返回给前端,并设置safe和ensure_ascii参数'''
return JsonResponse(serializer.data,safe=False,json_dumps_params={"ensure_ascii":False})
反序列化功能的局部钩子和全局钩子
1.局部钩子和全局钩子在序列化器中的使用
class StudentSerizlizer(serializers.Serializer): name = serializers.CharField(max_length=4,validators=[check666,])
age = serializers.IntegerField(max_value=18)
class_null = serializers.CharField() '''required=False,allow_null=True允许字段为空,也就是不用传递过来这个data'''
description = serializers.CharField(required=False,allow_null=True) '''allow_blank=True 允许只为空字符串'''
description = serializers.CharField(allow_blank=True) '''局部钩子:针对单个属性对应的数据进行校验'''
def validate_name(self,val):# val就是你对应字段的内容,函数名固定写法:validate_字段名
if '777' in val:
raise serializers.ValidationError('不能有777')
return val # 如果没有错误,需要return这个属性数据 '''全局钩子: 主要是针对多个属性数据进行校验'''
def validate(self,data): '''data是反序列化后得到的字典'''
print(data) # OrderedDict([('name', 'c778'), ('age', 6), ('class_null', '1'), ('description', '123')]) age = data.get('age')
class_null = data.get('age') if age == class_null:
raise serializers.ValidationError('age和class——null不能相等') return data #如果没有错误,全局钩子要return所有数据
2.反序列化相关校验的执行顺序
举个例子,代码如下所示
class StudentSerizlizer(serializers.Serializer): # 1.字段限制
name = serializers.CharField(max_length=4,validators=[check666,])
age = serializers.IntegerField(max_value=18) # 2.局部钩子
def validate_name(self,val):
pass def validate_age(self,val):
pass # 3.全局钩子
def validate(self,data):
pass
执行顺序:
1.先执行name中CharField参数中的规则
2.执行name的局部钩子函数
3.执行age的IntegerField参数中的规则
4.执行age的局部钩子函数
5.执行全局钩子函数
Tip:is_valid中的raise_exception参数
serializer.is_valid(raise_exception=True) # 等于True会主动抛出异常
反序列化的数据保存功能
反序列化的数据保存,一共有两种方式:
方式一:直接在视图中保存
# 方式1:直接在视图中保存
class StudentView(View):
def post(self,request):
if ser.is_valid():
ret = models.Student.objects.create(
**ser.validated_data
)
serializer = StudentSerizlizer(instance=ret) return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False}) else:
print(ser.errors)
return JsonResponse({'error':'有字段错误'})
方式二:视图中通过save方法来触发序列化器类中的create方法
# 方式2 save+create
# 在序列化器中定义create方法来数据的保存
class StudentSerizlizer(serializers.Serializer):
name = serializers.CharField(max_length=4,validators=[check666,])
age = serializers.IntegerField(max_value=18)
...... def create(self, validated_data): # 定义create方法
'''self.validated_data和validated_data结果是相同的,所以直接用validated_data即可'''
print(validated_data)
ret = models.Student.objects.create(
**validated_data
)
return ret # 视图中通过save方法来触发,序列化器类中的create方法
class StudentView(View):
def post(self,request):
if ser.is_valid(): '''通过save()方法去触发序列化器中的create方法'''
instance = ser.save() # 得到create方法的返回值
serializer = StudentSerizlizer(instance=instance) return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False})
反序列化的数据更新功能
# 在序列化器中定义update方法来数据的更新
class StudentSerizlizer(serializers.Serializer): name = serializers.CharField(max_length=4,validators=[check666,])
age = serializers.IntegerField(max_value=18)
... # 做更新动作
def update(self, instance, validated_data):
'''instance,validated_data?????'''
print(instance) # id=2 的模型类对象
print(validated_data) # 反序列化后的数据
instance.name = validated_data['name']
instance.age = validated_data['age']
instance.class_null = validated_data['class_null']
instance.description = validated_data['description']
instance.save()
return instance # 视图部分
class StudentView(View):
def put(self,request): '''要更新的数据'''
data = {
'id': 2,
'name':'xx',
'age':8,
'sex':0,
'class_null':'9',
'description':'xx', }
obj = models.Student.objects.get(id=data.get('id')) '''instance=obj用来指定这个save()触发的是序列化器中的update方法,而不是create方法,data就是你要更新的数据'''
s_obj = StudentSerizlizer(instance=obj,data=data) '''判断反序列化之后的数据是否合法'''
if s_obj.is_valid():
s_obj.save() # 触发序列化器类的update方法 else:
return JsonResponse({'error':'数据错误'})
Field字段参数:read_only和write_only
read_only和write_only是field字段里面的参数,也是用来对字段做限制的
from rest_framework import serializers class StudentSerizlizer(serializers.Serializer):
'''read_only=True,序列化时序列化出该字段数据,反序列化校验时不要校验这个数据'''
id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=4,) '''write_only=True,序列化时不序列化这个字段数据,反序列校验时需要客户端传递这个数据过来进行校验'''
age = serializers.IntegerField(max_value=18,write_only=True) class_null = serializers.CharField() description = serializers.CharField(allow_blank=True)
视图部分这样写:
from django.shortcuts import render
from django.views import View
from students import models
from .serializers import StudentSerizlizer
from django.http import JsonResponse
class StudentView(View): def get(self,request):
all = models.Student.objects.all()
serializer = StudentSerizlizer(instance=all, many=True) return JsonResponse(serializer.data, safe=False, json_dumps_params={'ensure_ascii':False}) def post(self,request): print(request.POST) data = {
'name':request.POST.get('name'),
'sex':request.POST.get('sex'),
'age':request.POST.get('age'),
'class_null':request.POST.get('class_null'),
'description':request.POST.get('description'),
}
serializer = StudentSerizlizer(data=data)
serializer.is_valid()
print(serializer.errors)
print('正确数据:',serializer.validated_data) return JsonResponse({'xx':'xx'})
Field字段参数:partial参数
partial参数默认为False,若partial=True则代表只需要校验传入给序列化器的数据(data),其他的字段不校验.适用于部分数据更新
应用场景:
比如在序列化器中加入定义了五个字段。
如果用户在前端提交/更新数据时,必须要将五个字段都提交,否则就会报错。
但是在现实应用场景下,有很多情况是不需要将五个字段全部提交的。比如数据更新
这个时候想要更改,但是序列化器的代码已经成型了,不太好进行修改。 【eg:提交需要提交5个字段,更新提交2个字段】
class StudentView(View):
def put(self,request): '''要更新的数据'''
data = {
'name':'chao',
'age':18
} '''partial=True:只需要校验传入给序列化器的数据(data),其他的字段不校验.适用于部分数据更新'''
serializer = StudentSerizlizer(data=data,partial=True)
serializer.is_valid()
print(serializer.errors)
print('正确数据:', serializer.validated_data) return JsonResponse({'ss': 'kk'})
模型类序列化器的使用:Modelserializer
1.Modelserializer的简单介绍
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
基于模型类自动生成一系列字段
基于模型类自动为Serializer生成validators,比如unique_together
包含默认的create()和update()的实现
2.Modelserializer的使用
models.py
....
serializers.py
from rest_framework import serializers
from students.models import Student
class StudentModelSerializer(serializers.ModelSerializer): # 如果模型类序列化器,必须 1.声明本次调用是哪个模型,2.模型里面的哪些字段
class Meta:
model = Student
fields = ["id","name","age","description","sex"]
# fields = "__all__" # 表示操作模型中的所有字段 # 添加额外的验证选项
exclude = ['id',] # 排除字段
extra_kwargs = {
"sex":{"write_only":True,},
"id":{"read_only":True,}
}
views.py
class StudentViewSet(View): def post(self,request): data = request.POST
serializers = StudentsSerializer(data=data) status = serializers.is_valid() student = serializers.save() # 上面使用的ModelSerializer,所以不需要我们自己写create方法了
print(student)
return JsonResponse({'msg':'henhao'})
drf:视图相关
1.APIView
原来的视图都是继承View类
class StudentView(View):
def get:
pass
......
而drf提供了一个APIView,如下所示
from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response """
1.drf提供的请求和响应类只能在drf封装过的子视图类中使用,也就是说不能再django.view.View中使用 2.只要类视图直接或者间接继承了APIView,则视图方法中使用的request,就是rest_framework.request.Request,同时,只有在APIVIew的子视图类中才可以使用rest_framework.respone.Response
"""
class StudentAPIView(APIView):
# class StudentAPIView(View): #之前的写法
def get(self,request): print(request)
# <rest_framework.request.Request object at 0x11d733e90> return Response({'msg':'ok'})
2.APIView中的request
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。这里我们可以自行写一个接口测试一下django原来的模式是解析不了json数据的,drf可以解析。但是需要注意的是:客户端如果传递过来的是json数据,那么request.data获取到的字典类型数据,不是querydict类型,也就没有了getlist方法,多选的数据,通过get就能取出来。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
from rest_framework.views import APIView class UserView(APIView): def get(self,request):
'''当我们访问http://127.0.0.1:8001/req/students/?age=100'''
print(request.GET) # <QueryDict: {'age': ['100']}>
print(request.query_params) # <QueryDict: {'age': ['100']}>
# request.GET和request.query_params是等价的 return JsonResponse({'xx':'xxxxx'}) def post(self,request):
print(request)
'''
1.当发送的数据格式为urlencoded类型时,request.POST和request.data等价
2.当发送过来的是json类型数据时,我们使用request.data属性能够获取到数据,request.data是无法获取json数据的
''' print(request.data) #{'username': 'xxxx', 'password': '123'},普通字典类型
# request.data能够获取到客户端发送过来的json类型数据,但是得到的结果为普通字典类型,但是如果是多选数据,不能使用getlist方法获取 return JsonResponse({'xx': 'xxxxx'})
3.APIView中的response
1.response介绍
REST framework提供了一个响应类Response
,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
我们后端如果通过Response来想用数据时,通过postman发送get请求获取数据,你会发现得到的是纯json数据,但是通过浏览器访问时会的到一个页面。这是为什么呢?drf的APIView在响应内容的时候会自动通过请求头中的浏览器信息来进行数据的回复(Response),如果是浏览器,那么返回的就是个页面(当然我们也可以不让他返回页面,可设置的,后面说)如果不是浏览器,给你返回的就是纯json数据。这是由drf中配置的两个不同的响应类产生的效果,看下面的配置。
REST framework提供了Renderer
渲染器,用来根据请求头中的Accept
(客户端希望接收的数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。
# 查看drf的默认配置
from rest_framework import settings # 用户配置替换drf内部配置的写法
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
'rest_framework.renderers.JSONRenderer', # json渲染器
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览器API渲染器
)
}
2.response参数解释
# 引入Response
from rest_framework.response import Response # response里面的相关参数
return Response({},status=201,template_name=None,headers=None,content_type=None)
'''
{}:响应的数据...
status:状态码
template:用于自定义浏览器的响应页面
headers:自定义响应头键值对
content_type:.... '''
参数说明:
data
: 为响应准备的序列化处理后的数据;status
: 状态码,默认200;template_name
: 模板名称,如果使用HTMLRenderer
时需指明;就是有些人觉得Response返回的那个页面丑,那么就可以通过这个模板自行定制。headers
: 用于存放响应头信息的字典;比如放一些cookie啊或者一些自定制的响应头啊都可以,例如:return Response({'msg': 'ok'},status=204,headers={'xx':'oo'})content_type
: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据(accept请求头)来设置该参数。
3.状态码大全
# 查看所有状态码
from rest_framework import status HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511
Tip:响应状态码的两种书写方式
from rest_framework import status # 响应状态码方式一
return Response({'xx':'xxxxx'}, status=201) # 响应状态码方式二
return Response({'xx':'xxxxx'}, status=status.HTTP_201_CREATED)
day72:drf:的更多相关文章
- DRF如何序列化外键的字段
我觉得在有些应用场景下,这个操作是有用的,因为可以减少一个AJAX的请求,以增加性能. 当然,是二次请求,还是一次传输.这即要考虑用户体验,还要兼顾服务器性能. 一切是有条件的平衡吧.就算是一次传输, ...
- DRF限制访问频次
官方文档:https://www.django-rest-framework.org/api-guide/throttling/ 1.什么场景下需要限制访问频次呢? 1)防爬虫:爬虫可能会在短时间内大 ...
- DRF缓存
对于现在的动态网站来讲,所有的界面展示都是通过客户端请求服务端,服务端再去请求数据库,然后将请求到的数据渲染后返回给客户端.用户每次访问页面都需要去请求数据库,如果同时有多个人访问的话,对于我们的数据 ...
- drf相关问题
drf自定义用户认证: 登录默认 使用django的ModelBackend,对用户名和密码进行验证.但我们平时登录网站时除了用户名也可以用邮箱或手机进行登录,这就需要我们自己扩展backend 一. ...
- DRF 缓存解决方案 drf-extensions / redis
drf-extensions 概述 drf-extensions组件内部提供了 DRF 的本地内存方式的缓存方式 本地内存方式缓存在项目重启后则会消失 官方点击 这里 安装 pip3 install ...
- DRF 商城项目 - 用户( 登录, 注册,登出,个人中心 ) 逻辑梳理
用户登录 自定义用户登录字段处理 用户的登录时通过 手机号也可以进行登录 需要重写登录验证逻辑 from django.contrib.auth.backends import ModelBacken ...
- luffy项目后台drf搭建(1)
一 进入虚拟环境 打开crm,输入命令 workon luffy 虚拟环境使用文档 二 安装基本类库 pip install django pip install PymySQL pip instal ...
- DRF项目创建流程(1)
一 web应用模式 前后端不分离 前后端分离 二 RESTFUL API规范 REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态 ...
- DRF初识与序列化
一.Django的序列化方法 1.为什么要用序列化组件 做前后端分离的项目,我们前后端数据交互一般都选择JSON,JSON是一个轻量级的数据交互格式.那么我们给前端数据的时候都要转成json格式,那就 ...
随机推荐
- 内存管理初始化源码1:setup_arch
源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...
- hystrix总结之多返回值命令
继承HystrixCommand实现run方法的命令只能返回单一值,Hystrix也提供了方式可以让我返回一个Observable结果,然后持续监听运行结果. 继承HystrixObservableC ...
- 有关java反射的几个小方法的作用和区别
1.Class类中 getXXX()和getDeclaredXXX()的作用和区别: 前者获取某个类的所有公共(public)的字段(or方法or构造函数),包括父类.后者获取所有的字段(or方法or ...
- 刷题[BJDCTF2020]Mark loves cat
解题思路 打开网页,发现是一个博客,基本寻找博客挂载信息,源码等无果后,扫描后台.发现.git泄露 .git泄露 发现.git泄露后,使用Git Extract这款工具,可自动将源码clone到本地 ...
- 项目升级springboot2.0注意事项
一.pring boot 2.0以后, springboot jpa findById 返回类型变化@NoRepositoryBeanpublic interface CrudRepository&l ...
- mysql-2-where
#进阶2:条件查询 /* 语法: SELECT 查询列表 FROM 表名 WHERE 筛选条件 分类: 1.按条件表达式筛选:> < = != <> >= <= 2 ...
- 再玩树莓派(二)Jexus&.NetCore
接上一篇,操作系统弄好之后,轮到开发运行环境的搭建. 先说说目标,也就是我到底想搞什么飞机.先说说小目标吧. 现有一个手机App客户端,以答题小游戏作为其内容(例如:口算题,24点,科学百科等) 树莓 ...
- CLP(FD)有限域上的约束逻辑式编程
译自http://www.pathwayslms.com/swipltuts/clpfd/clpfd.html#_simple_constraints,SWI-Prolog官网所推荐的进阶教程.目前还 ...
- 请编写sql多语句表值函数统,计指定年份中每本书的销售总额
create table 图书表( 书号 varchar(50), 书名 varchar(50), 单价 int ) create table 销售表( 书号 varchar(50), 销售时间 da ...
- 054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述
054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述 本文知识点:数组概述 为什么要学习数组? 实际问题: 比如我们要对学生的成绩进行排序,一个班级 ...