1.DRF组件
详细文档:见附件
1.1 Web应用模式
在开发web应用中,有两种应用模式:
1.前后端不分离【客户端看到的内容和所有页面效果都是由服务端提供出来的】
2.前后端分离【把前端的界面效果(html,css,js分离到另一个服务端,Python服务端只需要返回数据即可)】
前端形成一个独立的网站,服务端构成一个独立的网站。
2.api接口
应用程序编程接口(Application Programming Interface,API接口),就是应用程序对外提供了一个操作数据的入口,这个入口可以是一个函数或类方法,也可以是一个url地址或者一个网络地址。当客户端调用这个入口,应用程序则会执行对应代码操作,给客户端完成相对应的功能。
当然,api接口在工作中是比较常见的开发内容,有时候,我们会调用其他人编写的api接口,有时候,我们也需要提供api接口给其他人操作。由此就会带来一个问题,api接口往往都是一个函数、类方法、或者url或其他网络地址,不断是哪一种,当api接口编写过程中,我们都要考虑一个问题就是这个接口应该怎么编写?接口怎么写的更加容易维护和清晰,这就需要大家在调用或者编写api接口的时候要有一个明确的编写规范!!!
为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们都需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少客户端和服务端双方之间的合作成本。
目前市面上大部分公司开发人员使用的接口实现规范主要有:restful、RPC。
restful:翻译成中文:资源状态转换(表征性状态转移)
- 把服务端提供的所有的数据/文件都看成资源, 那么通过api接口请求数据的操作,本质上来说就是对资源的操作了.
因此,restful中要求,我们把当前接口对外提供哪种资源进行操作,就把资源的名称写在url地址。
- web开发中操作资源,最常见的最通用的无非就是增删查改,所以restful要求在地址栏中声明要操作的资源是什么。然后通过http请求动词来说明对该资源进行哪一种操作
POST http://www.xxx.com/api/students/ 添加学生数据
GET http://www.xxx.com/api/students/ 获取所有学生
GET http://www.xxx.com/api/students// 获取id=pk的学生
DELETE http://www.xxx.com/api/students// 删除id=pk的一个学生
PUT http://www.xxx.com/api/students// 修改一个学生的全部信息 [id,name,sex,age,]
PATCH http://www.xxx.com/api/students// 修改一个学生的部分信息[age]
也就是说,我们仅需要通过url地址上的资源名称结合HTTP请求动作,就可以说明当前api接口的功能是什么了。restful是以资源为主的api接口规范,体现在地址上就是资源就是以名词表达。
1.3 RESTful API规范
REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中。
RESTful是一种专门为Web 开发而定义API接口的设计风格,尤其适用于前后端分离的应用模式中。
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
请求方法 | 请求地址 | 后端操作 |
---|---|---|
GET | /students | 获取所有学生 |
POST | /students | 增加学生 |
GET | /students/ |
获取编号为pk的学生 |
PUT | /students/ |
修改编号为pk的学生 |
DELETE | /students/ |
删除编号为pk的学生 |
restful规范是一种通用的规范,不限制语言和开发框架的使用。事实上,我们可以使用任何一门语言,任何一个框架都可以实现符合restful规范的API接口。
参考文档:http://www.runoob.com/w3cnote/restful-architecture.html
1.4 幂等性
接口实现过程中,会存在幂等性。所谓幂等性是指代客户端发起多次同样请求时,是否对于服务端里面的资源产生不同结果。如果多次请求,服务端结果还是一样,则属于幂等接口,如果多次请求,服务端产生结果是不一样的,则属于非幂等接口。
请求方式 | 是否幂等 | 是否安全 |
---|---|---|
GET | 幂等 | 安全 |
POST | 不幂等 | 不安全 |
PUT/PATCH | 幂等 | 不安全 |
DELETE | 幂等 | 不安全 |
1.DRF封装的流程
1.CBV
#调用的参数 as_view View类
#视图类中调用View视图做请求类型转发
from django.views import View
#调用返回类
from django.http import HttpResponse
路由中引用`as_view`做请求类型识别
2.DRF
#重新封装cbv的view类,新类为APIView
rest_framework.views.APIView
#重新封装cbv的HttpResponse类,新类为Response
rest_framework.response.Response
DRF在Django原有的基础上,新增了一个request对象继承了APIView视图类,并在django原有的HttpResponse响应类的基础上实现了一个子类rest_framework.response.Response响应类。两个类,都是基于内容协商来完成数据的格式转换的。
详细区别可参考:DEF的APIVIEW视图章节
3.Serializer
from rest_framework import serializers
1.序列化,序列化器会把模型对象转成字典,经过response以后变成json字符串
2.反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3.反序列化,完成数据校验功能
4.ModelSerializer
#封装了Serializer类,实现了自动序列化模型方法,ModelSerializer
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
视图
#cbv
View HttpResponse as_view
| | |
| | |
#def
APIView Response as_view Serializer
| | | |
| | | |
ModelSerializer
| | | |
| | | |
generics.GenericAPIView
(封装了部分增删改查查功能代码)
|
|
Mixin(混入类 ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin)
封装了增删该查查全部功能
|
|
GenericViewSet的视图子类
提供了请求方法
| |
| |
ModelViewSet的视图子类 routers(自动分发路由)
1. Django的CBV
之前我们用的django的视图函数叫FBV(也就是函数型视图函数),CBV(类视图函数)。类视图函数可以让代码看起来更简洁,用起来更方便
仅支持5种调用方式。实现“增删改查查”功能
类名称 | 请求方法 | 请求地址 | 后端操作 |
---|---|---|---|
get | GET | /xxxxxxxx | 获取所有数据 |
post | POST | /xxxxxxxx | 增加学生 |
get | GET | /xxxxxxxx/<pk> | 获取编号为pk的学生 |
puy | PUT | /xxxxxxxx/<pk> | 修改编号为pk的学生 |
delete | DELETE | /xxxxxxxx/<pk> | 删除编号为pk的学生 |
编写类的的时候必须要写完整的字段名称,必须是小写
2. CBV的简单使用
视图类
from django.views import View
from django.http import HttpResponse
class Bookview(View):
def get(self,request):
return HttpResponse("get...")
def post(self,request):
return HttpResponse("post...")
class BkView(View):
def get(self,request,id):
id = id
return HttpResponse("书籍id为"+id)
def put(self,request,id):
id = id
return HttpResponse("更新书籍id为"+id)
def delete(self,request,id):
id = id
return HttpResponse("删除书籍id为"+id)
路由
因为“删改查需要穿id,所以需要两条路由线路”
#路由列表
urlpatterns = [
path('book/',views.Bookview.as_view()), #查询所有/添加
re_path('book/(\d+)/',views.BkView.as_view()), #修改/删除/查询单一
]
postman测试get请求:
postman测试post请求:
2.1 VBC的源码解析
#按照调用逻辑>
path('book/',views.Bookview.as_view()),
class Bookview(View):
def get(self,request):
return HttpResponse("get...")
def post(self,request):
return HttpResponse("post...")
1.项目启动,运行urls里面的as_view()函数,等待用户发起调用
2. 一旦用户发起请求,比如get请求访问/book/
3.Bookview类调用到View的as_view
class View:
@classonlymethod
def as_view(cls):
def view(request):
self = cls()
return self.dispatch(request, *args, **kwargs) #调用dispatch类
return view #调用as_views里面的小view
def dispatch(self, request):
handler = getattr(self, request.method.lower()) # 按请求方式分发(获取访问过来的请求方式,并转换成小写)
return handler(request, *args, **kwargs) #调用views的Bookview类的get/post等函数,得到的是get方法的响应结果
get请求访问/book/ => as_views() => view() => dispatch() => get()
3. CBV源码解析
3.1 面向对象知识点回顾
3.1.1继承
class Animal(object):
def __init__(self, name, age):
self.name = name
self.age = age
self.sleep() # 一定要明确self是谁
def sleep(self):
print("sleeping...")
class Dog(Animal):
def wangwang(self):
print("旺旺叫")
def sleep(self):
print("仰天睡...")
d = Dog("alex", 23)
3.1.2 反射
class Animal(object):
def __init__(self, name, age, init_func_str):
self.name = name
self.age = age
func = getattr(self, init_func_str)
func()
def sleep(self):
print("sleeping...")
class Dog(Animal):
def wangwang(self):
print("旺旺叫")
def sleep(self):
print("仰天睡...")
d = Dog("alex", 23, "sleep")
4.Django_Rest_Framework
核心思想: 大量缩减编写api接口的代码
Django REST framework(简称drf)是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
中文文档:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework
github: https://github.com/encode/django-rest-framework/tree/master
4.1 特点
- 提供了定义序列化器Serializer的方法,可以快速根据django ORM或者其他库自动序列化/反序列化;
- 提供了丰富的类视图、Mixin扩展类,简化视图的编写;
- 丰富的定制层级:函数视图、类视图、视图集合到自动生成API,满足各种需求;
- 多种身份认证和权限方式的支持;
- 内置了限流系统
- 可扩展性,插件丰富
4.2. 环境安装与配置
DRF需要以下依赖:
- Python (3.5 以上)
- Django (2.2 以上)
DRF是以Django子应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)
安装drf,前提是已经安装了django
# conda create -n drfdemo python=3.8
# pip install django==3.2.4 -i https://pypi.douban.com/simple
pip install djangorestframework -i https://pypi.douban.com/simple
可以正常引入表示安装成功:
import rest_framework
5.DRF的APIView视图
5.1 APIView的简单使用
rest_framework.views.APIView
APIView
是REST framework提供的所有视图的基类,继承自Django的View
父类。
相较于CBV,路由不变,视图不变,继承类给为APIView
,仍可以实现功能
from django.http import HttpResponse
#引入drf的apiview
from rest_framework.views import APIView
class Bookview(APIView):
def get(self,request):
return HttpResponse("get...")
def post(self,request):
return HttpResponse("post...")
class BkView(APIView):
def get(self,request,id):
id = id
return HttpResponse("书籍id为"+id)
def put(self,request,id):
id = id
return HttpResponse("更新书籍id为"+id)
def delete(self,request,id):
id = id
return HttpResponse("删除书籍id为"+id)
5.2 APIView的源码解析
'''
class Bookview(APIView):
def get(self,request):
return HttpResponse("get...")
class APIView(View):
@classmethod
def as_view(cls):
view = super().as_view() #调用父类的as_view方法
view.cls = cls
return view
def dispatch(self, request):
# (1)构建新的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
# (2)认证、权限、限流组件三件套
self.initial(request, *args, **kwargs)
# (3)分发
handler = getattr(self, request.method.lower()) # 按请求方式分发
return handler(request, *args, **kwargs)
class View:
@classonlymethod
def as_view(cls):
def view(request):
self = cls()
return self.dispatch(request, *args, **kwargs)
return view
# 路由
path('book/',views.Bookview.as_view()),
re_path('book/(\d+)/',views.BkView.as_view()),
# 一旦用户发起请求,比如get请求访问/book/,依然得到get方法的响应
get请求访问/book/ => View.view() => APIView.dispatch() => BookView.get()
'''
APIView
与View
的不同之处在于:
- 传入到视图方法中的是REST framework的
Request
对象,而不是Django的HttpRequeset
对象;
- 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端期望要求的格式;
- 任何
APIException
异常都会被捕捉到,并处理成合适格式的响应信息返回给客户端; - 重新声明了一个新的as_views方法并在dispatch()进行路由分发钱,会对请求的客户端进行身份认证、权限检查、流量控制。
DRF在Django原有的基础上,新增了一个request对象继承了APIView视图类,并在django原有的HttpResponse响应类的基础上实现了一个子类rest_framework.response.Response响应类。两个类,都是基于内容协商来完成数据的格式转换的。
request->parser->识别客户端请求头中的Content-Type来完成数据转换成->类字典(QueryDict,字典的子类)
response->renderer->识别客户端请求头的"Accept"来提取客户单期望的返回数据格式,-> 转换成客户端的期望格式数据
5.3、请求
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
5.3.1、常用属性
1 .data(解析post请求数据)
request.data
返回解析之后的请求体数据。类似于Django中标准的request.POST
和request.FILES
属性,但提供如下特性:
- 包含解析之后的文件和非文件数据
- 包含对POST、PUT、PATCH请求方式解析后的数据
- 利用REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据。
2 .query_params(解析get请求数据)
request.query_params
与Django标准的request.GET
相同,只是更换了更正确的名称而已。
3 .request._request
获取django封装的Request对象
5.3.2、基本使用
视图代码:
#引入drf的apiview
from rest_framework.views import APIView
from rest_framework.response import Response
class Bookview(APIView):
def get(self,request):
return Response("get...")
def post(self,request):
#获取请求体
bb = request.data
print(bb,type(bb)) #{'title': '红楼梦', 'price': 234, 'time': '2022-10-10'} <class 'dict'>
print(bb.get("title")) #红楼梦
return Response(request.data) #直接从请求体中提取数据转为json发送给客户端
class BkView(APIView):
def get(self,request,id): # # rest_framework.request.Request对象
## 获取查询字符串
bb = request.query_params
print(bb,type(bb))
# 没有参数情况下: <QueryDict: {}>
#有参数的情况下:<QueryDict: {'title': ['三国演义'], 'price': ['1688'], 'time': ['2020-10-01']}> <class 'django.http.request.QueryDict'>
# 所以,request.query_params的返回值操作和原来在django里面是一模一样的
print(bb.get("title")) #三国演义
print(bb.getlist("title")) #['三国演义']
id = id
return Response(request.query_params) #返回json数据
def put(self,request,id):
id = id
return Response("更新书籍id为"+id)
def delete(self,request,id):
id = id
return Response("删除书籍id为"+id)
获取post请求提
get获取请求提
5.4.响应
rest_framework.response.Response
REST framework提供了一个响应类Response
,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染器)成符合前端需求的类型。
REST framework提供了Renderer
渲染器,用来根据请求头中的Accept
(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用Content-Type方式处理响应数据,我们可以通过配置来修改默认响应格式。
可以在rest_framework.settings查找所有的drf默认配置项
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
'rest_framework.renderers.JSONRenderer', # json渲染器,返回json数据
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览器API渲染器,返回调试界面
)
}
5.4.2 构造方式
Response(data, status=None, template_name=None, headers=None, content_type=None)
drf的响应处理类和请求处理类不一样,Response就是django的HttpResponse响应处理类的子类。
data
数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer
渲染器处理data
。
data
不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer
序列化器序列化处理后(转为了Python字典类型)再传递给data
参数。
参数说明:
data
: 为响应准备的序列化处理后的数据;
status
: 状态码,默认200;template_name
: 模板名称,如果使用HTMLRenderer
时需指明;headers
: 用于存放响应头信息的字典;content_type
: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数
5.4.2.1 Response对象的属性
.data:传给response对象的序列化后,但尚未render处理的数据
.status_code:状态码的数字
.content:经过render处理后的响应数据
5.4.2.2.2 状态码
为了方便设置状态码,REST framewrok在rest_framework.status
模块中提供了常用http状态码的常量。
# 1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
# 2)成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
# 3)重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
# 4)客户端错误 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
# 5)服务器错误 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
6.序列化器-Serializer
作用:
1.序列化,序列化器会把模型对象转成字典,经过response以后变成json字符串
2.反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3.反序列化,完成数据校验功能
6.1 定义序列化器
Django REST framework中的serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
为了方便演示序列化器的使用,我们先创建一个新的子应用sers
python manage.py startapp sers
我们创建几个图书相关模型
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书籍名称")
price = models.IntegerField(verbose_name="价格")
pub_date = models.DateField(verbose_name="出版日期")
bread = models.IntegerField(verbose_name="阅读量")
bcomment = models.IntegerField(verbose_name="评论量")
publish = models.ForeignKey("Publish", on_delete=models.CASCADE, verbose_name="出版社")
authors = models.ManyToManyField("Author",verbose_name="作者")
def __str__(self):
return self.title
我们想为Book模型类提供一个序列化器,可以定义如下:
from rest_framework import serializers
#构建serializer序列化类
class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.IntegerField()
pub_date = serializers.DateField()
bread = serializers.IntegerField()
bcomment = serializers.IntegerField()
publish_id = serializers.IntegerField()
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
6.2 创建Serializer对象
定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
说明:
1.用于序列化时,将模型类对象传入instance参数
2.用户反序列化时,将要被反序列化的数据传入data参数
3.除了instance和data参数外,在构造Serializer时,还可通过context参数额外添加数据,如
serializer = AccountSerializer(account, context={'request': request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
- 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
- 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
- 序列化器的字段声明类似于我们前面使用过的表单系统。
- 开发restful api时,序列化器会帮我们把模型数据转换成字典.
- drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.
6.3 序列化字段
https://q1mi.github.io/Django-REST-framework-documentation/api-guide/fields_zh/
6.4.序列化器的使用
序列化器的使用分两个阶段:
1.处理客户端请求时,使用序列化器可以完成对数据的反序列化。
2.处理服务器响应时,使用序列化器可以完成对数据的序列化。
6.4.1.1 序列化
1.1.1 基本序列化
《1》 先查询出一个学生对象
from sers.models import Book
book = Book.objects.get(pk=1)
《2》 构造序列化器对象
from .serializers import BookSerializer
bookSer = BookSerializer(instance=book)
《3》获取序列化数据
通过data属性可以获取序列化后的数据
bookSer.data
# {'title': '乱世佳人', 'price': 335, 'pub_date': '2012-12-12'}
《5》如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
BookSerializer(instance=books, many=True)
6.4.1.2 反序列化
1.2.1 数据验证
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
可以设置required=False让校验字段可以为空!
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:
(1) validate_字段名
对<field_name>
字段进行验证,如
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
price = serializers.IntegerField(required=True)
pub_date = serializers.DateField(required=True)
def validate_title(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
测试
from sers.sers import BookSerializer
bs = BookSerializer(data={"title":"小王子","price":100})
bs.is_valid()
False
bs.errors
{'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')], 'pub_date': [ErrorDetail(string='This field is required.', code='required')]}
还有一种写法:
def title_django(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32,validators=[title_django,])
(2) validate
在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
price = serializers.IntegerField(required=False)
pub_date = serializers.DateField(required=False)
bread = serializers.IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
bcomment = serializers.IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
def validate_title(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
def validate(self, data):
bread = data.get("bread")
bcomment = data.get("bcomment")
if bread < bcomment:
raise serializers.ValidationError('阅读量小于评论量')
return data
测试
bs = BookSerializer(data={"title":"Django深入浅出","bread":100,"bcomment":200,"publish_id":1})
bs.is_valid()
False
bs.errors
{'non_field_errors': [ErrorDetail(string='阅读量小于评论量', code='invalid')]}s
1.2.2 反序列化-保存数据
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程,这个过程可以把数据转换成模型类队形。
可以通过实现create()和update()两个方法来实现。
class BookSerializer(serializers.Serializer):
"""图书数据序列化器"""
...
def create(self, validated_data):
"""新建"""
return instance
def update(self, instance, validated_data):
return instance
实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
book = serializer.save() #父类中封装了create、update等方法
1.如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用
2.相关,如果传递了instance实例,则调用save()方法的时候,update()被调用。
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)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
序列化器
声明序列化器,所有的序列化器都要直接或者间接继承与 Serializer
其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
(3) 附加说明
1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到
# request.user 是django中记录当前登录用户的模型对象serializer.save(owner=request.user)
2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
# Update `comment` with partial dataserializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
6.4.2、基于APIView的接口实现(序列化和反序列化)
urls.py
#路由列表
urlpatterns = [
path('book/',views.BookViews.as_view()),
re_path('book/(\d+)',views.BViews.as_view())
]
views.py
###########Serializer###########3
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from rest_framework import serializers
#构建serializer序列化类
class BookSerializer(serializers.Serializer):
"""
创建序列化器,序列化数据库字段
"""
title = serializers.CharField()
price = serializers.IntegerField()
pub_date = serializers.DateField()
bread = serializers.IntegerField()
bcomment = serializers.IntegerField()
publish_id = serializers.IntegerField()
def create(self, validated_data):
#创建类对象
new_book = Book.objects.create(**validated_data)
return new_book
def update(self, instance, validated_data):
Book.objects.filter(pk=instance.id).update(**validated_data)
instance = Book.objects.get(pk=instance.id)
return instance
class BookViews(APIView):
def get(self, request): #查询所有
book = Book.objects.all()
cc = BookSerializer(instance=book,many=True) #序列化操作
print(cc.data) #获取序列化之后的数据
return Response(cc.data)
def post(self,request): #添加
data = BookSerializer(data=request.data)
# print("data",data) # 打印request里面的boby数据
#进行数据校验,校验结果为True则保存,False则返回报错
if data.is_valid():
data.save()
return Response(data.data)
else:
return Response(data.errors)
class BViews(APIView):
def get(self,request,id): #查询单个值
bs = Book.objects.get(pk=id)
book = BookSerializer(instance=bs)
return Response(book.data)
def delete(self,request,id): #删除
Book.objects.get(pk=id).delete()
return Response("删除成功")
def put(self,request,id): #修改数据的部分信息
instance = Book.objects.get(pk=id)
bs = BookSerializer(data=request.data,instance=instance) #传入序列化器新的数据和旧数据
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
查询所有书籍
添加一本书籍
删除指定书籍
修改一本书籍
查询一本书籍
6.5.ModelSerializer-模型类序列化器
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个serializer类。
ModelSerlizer与常规的Serializer相同,但提供了:
- 基于模型类自动生成一系列字段
- 基础模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
(1)定义
例如我们创建一个BookInfoSerializer
class BookSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = Book
fields = '__all__'
- model指明参照哪个模型类
- fields指明为模型类的那些字段生成
我们可以在python manage.py shell中查看自动生成的BookSerialize
(2)指定字段
1.使用fields来明确字段,__all__
表示包含所有字段,也可以写明具体哪些字段,如
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ("id","title","price")
2.使用exclude可以明确排除掉哪些字段
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
exclude = ("id","publish","authors")
3.指明只读字段
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id', 'title', 'pub_date','bread','bcomment')
read_only_fields = ('id', 'bread', 'bcomment')
(3)添加额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = Book
fields = ('id', 'title', 'pub_date')
extra_kwargs = {
'bread': {'min_value': 0, 'required': True},
'bcomment': {'min_value': 0, 'required': True},
}
6.5.2.基础APIView实现ModelSerializer类调用
基于“基于APIView的接口实现(序列化和反序列化)”进行优化,调用ModelSerializer类
注意,只有序列化器改为引用serializers.ModelSerializer,并添加 class Meta类,其他部分都没动。
所完成的功能和上面实现的是一样的。
###########serializers.ModelSerializer###########3
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from rest_framework import serializers
#构建serializer序列化类
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
def create(self, validated_data):
new_book = Book.objects.create(**validated_data)
return new_book
def update(self, instance, validated_data):
Book.objects.filter(pk=instance.id).update(**validated_data)
instance = Book.objects.get(pk=instance.id)
return instance
class BookViews(APIView):
def get(self, request): #查询所有
book = Book.objects.all()
cc = BookSerializer(instance=book,many=True) #序列化操作
print(cc.data) #获取序列化之后的数据
return Response(cc.data)
def post(self,request): #添加
data = BookSerializer(data=request.data)
# print("data",data) # 打印request里面的boby数据
#进行数据校验,校验结果为True则保存,False则返回报错
if data.is_valid():
data.save()
return Response(data.data)
else:
return Response(data.errors)
class BViews(APIView):
def get(self,request,id): #查询单个值
bs = Book.objects.get(pk=id)
book = BookSerializer(instance=bs)
return Response(book.data)
def delete(self,request,id): #删除
Book.objects.get(pk=id).delete()
return Response("删除成功")
def put(self,request,id): #修改数据的部分信息
instance = Book.objects.get(pk=id)
bs = BookSerializer(data=request.data,instance=instance) #传入序列化器新的数据和旧数据
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
7.视图
Django REST framework提供的视图的主要作用:
- 控制序列化器执行(检验、保存、转换数据)
- 控制数据库模型的操作
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
7.1.GenericAPIView[通用视图类]
通用视图类主要作用就是把视图中的独特的代码抽取出来,让视图方法中的代码更加通用,方便把通用代码进行简写
rest_framework.generics.GenericAPIView
继承自APIView
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常再使用时,可搭配一个或多个Mixin扩展类。
1.1 提供的关于序列化器使用的属性和方法
(1)get_serializer_class(self)
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回serializer_class,可以重写
(2)get_serializer(self, args, *kwargs)
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
- request 当前视图的请求对象
- view 当前请求的类视图对象
- format 当前请求期望返回的数据格式
(3)get_queryset(self)
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset
属性,可以重写,例如:
def get_queryset(self):
user = self.request.user
return user.accounts.all()
(4)get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
serializer = self.get_serializer(book)
return Response(serializer.data)
其他可以设置的属性
- pagination_class 指明分页控制类
- filter_backends 指明过滤控制后端
7.2. 通用视图类的应用
针对于前面的代码做优化
1.路由
#路由列表
urlpatterns = [
path('book/',views.BookViews.as_view()),
re_path('book/(?P<pk>\d+)/',views.BViews.as_view())
]
2.视图
#设计增删改查查接口
#序列化器
from rest_framework.response import Response
from .models import Book
from rest_framework import serializers
from rest_framework.generics import GenericAPIView
from rest_framework import status
#构建serializer序列化类
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
class BookViews(GenericAPIView):
queryset = Book.objects.all() #获取数据的对象,定义好的名称
serializer_class = BookSerializer #序列化器
def get(self, request): #查询所有
# cc = BookSerializer(instance=self.get_queryset(),many=True) #序列化操作
cc = self.get_serializer(instance=self.get_queryset(),many=True) #序列化操作
print(cc.data) #获取序列化之后的数据
return Response(cc.data) #针对serializer.instance
def post(self,request): #添加
# print("data",data) # 打印request里面的boby数据
#构建序列化器对象
data = self.get_serializer(data=request.data)
#进行数据校验,校验结果为True则保存,False则返回报错
if data.is_valid():
#将数据保存到数据库中
data.save()
return Response(data.data)
else:
#校验失败
return Response(data.errors)
class BViews(GenericAPIView):
queryset = Book.objects.all() #获取数据的对象,定义好的名称
serializer_class = BookSerializer #序列化器
def get(self,request,pk): #查询单个值
book = self.get_serializer(instance=self.get_object(),many=False)
return Response(book.data)
def delete(self,request,pk): #删除
self.get_object().delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def put(self,request,pk): #修改数据的部分信息
bs = self.get_serializer(data=request.data,instance=self.get_object()) #传入序列化器新的数据和旧数据
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
7.3. 5个视图扩展类
也叫混入类(Mixin)。
作用:
提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIView通用视图基类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法
(1)ListModelMixin
列表视图扩展类,提供list(request, *args, **kwargs)
方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
(2)CreateModelMixin
创建视图扩展类,提供create(request, *args, **kwargs)
方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
(3)RetrieveModelMixin
详情视图扩展类,提供retrieve(request, *args, **kwargs)
方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
详情视图扩展类,提供`retrieve(request, *args, **kwargs)`方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
(4)UpdateModelMixin
更新视图扩展类,提供update(request, *args, **kwargs)
方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)
方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin:
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
(5)DestroyModelMixin
删除视图扩展类,提供destroy(request, *args, **kwargs)
方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class DestroyModelMixin:
"""
Destroy a model instance.
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
1.2 整体代码,使用GenericAPIView结合视图扩展类,实现5个基本api接口,视图代码:
优化之前的代码
视图类
###########基于MinIN混合类的接口实现###########3
from .models import Book
from rest_framework import serializers
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
#构建serializer序列化类
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
class BookViews(ListModelMixin,CreateModelMixin,GenericAPIView):
queryset = Book.objects.all() #获取数据的对象,定义好的名称
serializer_class = BookSerializer #序列化器
def get(self, request): #查询所有
return self.list(request)
def post(self,request): #添加
return self.create(request)
class BViews(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
queryset = Book.objects.all() #获取数据的对象,定义好的名称
serializer_class = BookSerializer #序列化器
def get(self,request,pk): #查询单个值
return self.retrieve(request,pk)
def delete(self,request,pk): #删除
return self.destroy(request,pk)
def put(self,request,pk): #修改数据的部分信息
return self.update(request,pk)
7.4.GenericAPIView的视图子类
(1)CreateAPIView
提供了post方法,内部调用了create方法
继承自: GenericAPIView、CreateModelMixin
(2)ListAPIView
提供了get方法,内部调用了list方法
继承自:GenericAPIView、ListModelMixin
(3)RetrieveAPIView
提供了get方法,内部调用了retrieve方法
继承自: GenericAPIView、RetrieveModelMixin
(4)DestoryAPIView
提供了delete方法,内部调用了destory方法
继承自:GenericAPIView、DestoryModelMixin
(5)UpdateAPIView
提供了put和patch方法,内部调用了update和partial_update方法
继承自:GenericAPIView、UpdateModelMixin
(6)ListCreateAPIView
提供了get和post方法,内部调用了list和create方法
继承自:GenericAPIView、ListModelMixin、CreateModelMixin
(7)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
(8)RetrieveDestoryAPIView
提供 get、delete方法
继承自:GenericAPIView、RetrieveModelMixin、DestoryModelMixin
(9)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
##########基于MinIN混合类的接口实现 再封装 ###########3
from .models import Book
from rest_framework import serializers
from rest_framework.generics import GenericAPIView
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
#构建serializer序列化类
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
class BookViews(ListCreateAPIView):
queryset = Book.objects.all() #获取数据的对象,定义好的名称
serializer_class = BookSerializer #序列化器
class BViews(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all() #获取数据的对象,定义好的名称
serializer_class = BookSerializer #序列化器
7.5 视图集
1、GenericViewSet
继承自GenericAPIView和ViewSetMixin,作用让视图集的视图代码变得更加通用,抽离独特代码作为视图类的属性。
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView
,所以还需要继承GenericAPIView
。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView
与ViewSetMixin
,在实现了调用as_view()时传入字典(如{'get':'list'}
)的映射处理工作的同时,还提供了GenericAPIView
提供的基础方法,可以直接搭配Mixin扩展类使用。
视图代码:
from rest_framework.viewsets import GenericViewSet
class BookView(GenericViewSet):
def list(self, request):
books = Book.objects.all()
bs = BookSerializer(instance=books, many=True)
return Response(bs.data)
def create(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def retrieve(self, request, pk):
book = Book.objects.get(pk=pk)
bs = BookSerializer(instance=book)
return Response(bs.data)
def update(self, request, pk):
instance = Book.objects.get(pk=pk)
bs = BookSerializer(instance=instance, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self, request, pk):
Book.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
路由
from django.urls import path, re_path
from vset.views import BookView
urlpatterns = [
# path("set", views.BookView.as_view({"http请求":"视图方法"})),
path("books/", BookView.as_view({
"get": "list",
"post": "create"
})),
re_path("^books/(?P<pk>\d+)$", BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "delete",
})),
]
集合我们上面学习的模型扩展类,实现简写操作,视图,代码:
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
DestroyModelMixin
class BookView(GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin,
DestroyModelMixin):
queryset = Book.objects
serializer_class = BookSerializer
1.2 ModelViewSet和ReadOnlyModelViewSet
ModelViewSet继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
ReadOnlyModelViewSet承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin。
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = Book.objects
serializer_class = BookSerializer
7.6. 路由Routers
对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。
REST framework提供了两个router
- SimpleRouter
- DefaultRouter
1) 创建router对象,并注册视图集,例如
from rest_framework import routers
router = routers.DefaultRouter()
router.register('book', BookView, base_name='book')
register(prefix, viewset, base_name)
- prefix 该视图集的路由前缀
- viewset 视图集
- base_name 路由别名的前缀
如上述代码会形成的路由如下:
^book/$ name: book-list
^book/{pk}/$ name: book-detail
2)添加路由数据
可以有两种方式:
urlpatterns = [
...
]
urlpatterns += router.urls
或
urlpatterns = [
...
path('^', include(router.urls))
]
路由代码:
from rest_framework.routers import DefaultRouter
from django.urls import path,include,re_path
from . import views
from rest_framework import routers
"""使用drf提供路由类router给视图集生成路由列表"""
# 实例化路由类
# drf提供一共提供了两个路由类给我们使用,他们用法一致,功能几乎一样
router = routers.DefaultRouter()
# 注册视图集
# router.register("路由前缀",视图集类)
router.register('book',views.BookViews)
#路由列表
urlpatterns = [
# path('book/',views.BookViews.as_view({"get":"list","post":"create"})),
# re_path('book/(?P<pk>\d+)/',views.BookViews.as_view({"get":"retrieve","put":"update","delete":"destroy"})),
]
print(router.urls)
# 把生成的路由列表追加到urlpatterns
urlpatterns += router.urls
8.restframework使用JWT验证
django4.0及之后将将不无法使用jwt
(1)安装jwt
pip install djangorestframework-jwt -i https://mirrors.aliyun.com/pypi/simple/
1.2 配置jwt
settings.py设置
# 配置JWT
REST_FRAMEWORK = {
# 自定义异常处理
'EXCEPTION_HANDLER': 'uric_api.utils.exceptions.custom_exception_handler',
#在全局做自定义权限限制(如需要开启全局权限,则不需要配置下面 1.2.1步骤)
# 'DEFAULT_PERMISSION_CLASSES': (
# 'rest_framework.permissions.IsAuthenticated',
# ),
# 在全局做自定义认证
'DEFAULT_AUTHENTICATION_CLASSES': (
# jwt认证
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
import datetime
JWT_AUTH = {
# jwt的有效时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=120),
#是否自动更新token
# 'JWT_ALLOW_REFRESH': True,
}
我们django创建项目的时候,在settings配置文件中直接就给生成了一个serect_key,我们直接可以使用它作为我们jwt的serect_kek,其实djangorestframework-jwt默认配置中就使用的它。
1.2.1 在局部配置token认证
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class HostView(APIView):
# 用户登录限制
"""
AllowAny 允许所有用户,默认权限
IsAuthenticated 仅通过登录认证的用户
IsAdminUser 仅管理员用户
IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。
"""
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated]
urls.py 获取认证token
from django.contrib import admin
from django.urls import path,include
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('login/',obtain_jwt_token) #新增行
]
操作完以上步骤即可整合JWT到框架中
1.3、使用Postman或其他工具测试Token
创建用户
python manage.py createsuperuser
postman获取用户的token
携带token请求其他数据
保证请求的header中包含了Authorization的token,其中token前要加JWT(手动空格)