drf入门
drf入门
目录
- 前后端开发模式
- API接口
- 接口测试工具
- restful规范
- 序列化反序列化
- djangorestframework快速使用
- APIView 基本使用
- APIView 源码分析
- Request 类源码分析
前后端开发模式
在web开发中前后端有两种开发模式,分别是前后端混合开发和前后端分离开发
就目前形势来讲,前后端分离开发已成大势
前后端混合开发
-
前后端混合开发-----》模板,使用模板语法渲染模板
前后端混合开发需要后端人员通过前端写好的html页面来套模板语法完成后端代码的编写
-
前端后台管理模板
layui+jquery
bootstrap+jquery
前后端分离开发
前后端分离只需要前端写好前端的代码,后端完成后端的代码,分别通过各自的接口测试,最后组合起来即可
-
后端
后端人员只负责写接口(API接口),使用postman接口测试工具测试
-
前端
前端人员只负责写前端,写的过程中使用mock数据
-
总合
将前后端联调项目,最后交付于测试
API接口
-
什么是API接口
通过网络,规定了前后台信息交互规则的url链接,也就是前后台信息交互的媒介
-
Web API接口的四大特点
①url:长得像返回数据的url链接
https://api.map.baidu.com/place/v2/search
②请求方式:get、post、put、patch、delete
采用get方式请求上方接口
③请求参数:json或xml格式的key-value类型数据
ak:6E823f587c95f0148c19993539b99295 region:上海 query:肯德基 output:json
④响应结果:json或xml格式的数据
上方请求参数的output参数值决定了响应数据的格式
接口测试工具postman
Postman是一款接口调试工具,是一款免费的可视化软件,同时支持各种操作系统平台,是测试接口的首选工具。
-
用途
API接口写好,后端人员要测试,不可能在浏览器里测试,故而使用接口测试工具测试
-
接口测试工具postman本质
模拟发送http请求
-
接口测试软件
接口测试软件有很多,例如postwoman,但最常用的接口测试软件还是postman
-
下载安装
官方下载:https://www.postman.com/downloads/
安装:一路到底,傻瓜式安装
-
工作面板
restful规范
REST全称是Representational State Transfer,中文意思是表述:表征性状态转移
RESTful是一种定义Web API接口的设计风格,尤其适用于前后端分离的应用模式中
restful规范有10点---》规范,公司有自己的风格规范
1.数据的安全保障
-
url链接一般都采用https协议进行传输
为了保证数据安全使用https协议传输
2.接口特征表现
-
用api关键字标识接口url
https://api.baidu.com https://www.baidu.com/api
该请求url链接是完成前后台数据交互的
3.多数据版本共存
一个接口可能有多个版本
例如:
https://api.baidu.com/v1
https://api.baidu.com/v2
url链接中的v1、v2就是不同数据版本的体现(只有在一种数据资源有多版本情况下)
4.数据即是资源,均使用名词(可复数)
-
接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
https://api.baidu.com/users https://api.baidu.com/books https://api.baidu.com/book
一般提倡用资源的复数形式,在url链接中奖励不要出现操作资源的动词
-
特殊的接口可以出现动词,因为这些接口一般没有一个明确的资源,或是动词就是接口的核心含义
https://api.baidu.com/place/search https://api.baidu.com/login
5.资源操作由请求方式决定
-
操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查动作
-获取数据:get请求
-删除数据:delete请求
-新增数据:post请求
-修改数据:put,patch请求
请求地址一样,通过请求方式决定对资源进行什么操作
6.过滤
通过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
7.响应状态码
-
http状态码:
① 1xx:表示请求正在处理,一般看不到
② 2xx: 表示请求处理成功, 200:成功请求
201:创建成功
③ 3xx: 重定向
301: 永久重定向
302: 临时重定向
④ 4xx: 客户端错误
403 :请求无权限
404 :请求路径不存在
⑤ 5xx :服务端错误
500: 服务器异常
8.错误处理,应返回错误信息,error当做key
{code:100,msg:成功}
9.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范
GET /collection:返回资源对象的列表(数组)[{},{}]
GET /collection/resource:返回单个资源对象 {}
POST /collection:返回新生成的资源对象 {}
PUT /collection/resource:返回完整的资源对象 {}
PATCH /collection/resource:返回完整的资源对象 {}
DELETE /collection/resource:返回一个空文档
-获取所有:{code:100,msg:成功,data:[{name:三体,price:99},{name:西游记,price:88}]}
-获取单条:{code:100,msg:成功,data:{name:三体,price:99}}
-新增数据:{code:100,msg:新增成功,data:{name:西游记,price:99}}
-修改数据:{code:100,msg:修改成功,data:{name:西游记v2版本,price:99}}
-删除数据:{code:100,msg:删除成功}
10.响应中带链接
# Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(罗餐厅)",
"img": "https://image.baidu.com/kfc/001.png"
}
...
]
}
序列化、反序列化
API接口开发最核心,最常见的一个过程就是序列化。所谓序列化就是把数据转换格式
-
序列化的两个阶段
-
序列化
把我们识别的数据转换成指定的格式提供给别人
-例如:我们在django中获取到的数据默认是模型对象(queryset),但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。
-
反序列化
把别人提供的数据转换/还原成我们需要的格式
-
django Rest_Framework快速使用
-
核心思想
缩减编写api接口的代码
-
什么是 django Rest_Framework
Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。
在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作
REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
-
特点
①提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化
②提供了丰富的类视图、Mixin扩展类,简化视图的编写
③丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要
④多种身份认证和权限认证方式的支持
⑤内置了限流系统
⑥直观的API web界面
⑦可扩展性,插件丰富
-
使用django这个web框架,开发前后端分离项目(模板渲染),只写接口
①使用JsonResponse返回即可---》原生django
②djangorestframework方便咱们快速写出符合restful规范的接口
-
写接口 的五种类型
①获取所有 get
②获取单个 get
③新增一条 post
④修改一条 put/patch
⑤删除一条 delete
对于表来说,快速实现五个接口
-
安装drf
pip3 install djangorestframework
-
urls.py
from django.contrib import admin from django.urls import path from rest_framework.routers import SimpleRouter from app01 import views router = SimpleRouter() router.register('books', views.BookView) urlpatterns = [ path('admin/', admin.site.urls), ] urlpatterns += router.urls
-
views.py
from .models import Book from rest_framework.viewsets import ModelViewSet from .serializer import BookSerializer class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
-
models.py
from django.db import models class Book(models.Model): name = models.CharField(max_length=32) price = models.CharField(max_length=32) publish = models.CharField(max_length=32)
-
serializer.py
from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = '__all__'
-
通过postman测试
cbv源码分析
-
url路由
path('test/', views.TestView.as_view()),
第一个参数是路径,第二个参数是试图函数的内存地址(视图类执行as_view这个类方法,把它执行完,结果放在第二个参数上:我们猜执行完的结果是个函数内存地址)
-
查看as_view()源码
找as_view,去TestView类中找,找不到,没有,去父类中找View @classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): return self.dispatch(request, *args, **kwargs) return view
当请求来了,路由匹配成功,会执行view(request)
其本质就是执行 self.dispatch(request, *args, **kwargs)
-
去View中找到了dispatch
def dispatch(self, request, *args, **kwargs): # 请求方式转成小写,假设 get 请求,符合if条件 if request.method.lower() in self.http_method_names: # 反射 getattr(对象,'字符串','默认值') # self是TestView的对象 # handler 就是TestView类的get方法 handler = getattr(self, 'get', self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) # get(request)
APIView基本使用
drf 是一个第三方的app,只能再django上使用
-
安装drf
pip3 install djangorestframework
安装了drf后,导入一个视图类APIView,所有后期要使用drf写视图类,都是继承APIView及其子类
-
在后端上获取所有的数据对象接口
使用View+JsonResponse写
class BookView(View):
def get(self, request):
print(type(request))
book_list = Book.objects.all()
# book_list是queryset对象不能直接序列化,只能通过for循环一个个拼成列表套字典的形式
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return JsonResponse(res_list,safe=False,json_dumps_params={'ensure_ascii':False}) # 只能序列化字典和列表,
使用APIView+drf的Response写
- 使用 APIView+drf的Response 前需要注册 rest_framework 这个app
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
class BookView(APIView): # APIView继承自django的View
def get(self, request):
print(request._request)
print(type(request._request))
book_list = Book.objects.all()
# book_list是queryset对象不能直接序列化,只能通过for循环一个个拼成列表套字典的形式
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return Response(res_list)
APIView源码分析
视图类继承APIView后,执行流程就发生了变化,这个变化就是整个的drf的执行流程
-
url路由
path('test/', views.TestView.as_view()),
第一个参数是路径,第二个参数是试图函数的内存地址(视图类执行as_view这个类方法,把它执行完,结果放在第二个参数上:我们猜执行完的结果是个函数内存地址)
-
先找视图类的as_view,即【APIView_view】,自身没有as_view,再找其父类APIview,查看APIView源代码
@classmethod def as_view(cls, **initkwargs): # 又调用了父类(View)的as_view view = super().as_view(**initkwargs) return csrf_exempt(view)
APIView中也没有as_view,利用super方法调用了其父类(view)中的as_view
csrf_exempt(view): 返回这个 就相当于往后的请求都不用再做csrf的校验了,就相当于再函数上加了装饰器
@csrf_exempt def index(request): pass
本质等同于 index=csrf_exempt(index)
-
请求来了,路由匹配成功会执行, View类的as_view类方法内的view闭包函数(但是没有了csrf认证),
def view(request,*args, ** kwargs): return self.dispatch(request,*args, ** kwargs)
真正的执行,执行self.dispatch就是APIView的dispatch
-
APIView的dispatch
def dispatch(self, request, *args, **kwargs): # 参数的request是原来的django原生的request # 下面的request,变成了drf提供的Request类的对象---》return Request(。。。) request = self.initialize_request(request, *args, **kwargs) # self 是视图类的对象,视图类对象.request=request 新的request self.request = request try: # 执行了认证,频率,权限 [不读] self.initial(request, *args, **kwargs) # 原来的View的dispatch的东西 if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: # 如果出了异常,捕获异常,处理异常,正常返回 # 在执行三大认证和视图类中方法过程中,如果出了异常,是能被捕获并处理的---》全局异常的处理 response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
-
总结
①只要继承APIView都没有csrf的认证了
②以后视图类中使用的request对象,已经变成了drf提供的Request类的对象了
③执行视图类的方法之前,执行了3大认证(认证,权限,频率)
④在执行三大认证和视图类的方法过程中只要报错,都会被捕获处理
Request类源码分析
-
视图类中使用的request对象,已经变成了drf提供的Request类的对象了
-
原生djagno 的request是这个类的对象
这个类 : django.core.handlers.wsgi.WSGIRequest
-
drf的request是这个类的对象:
这个类 : rest_framework.request.Request
-
-
request已经不是原来的request了,还能像原来的request一样使用吗?
虽然request已经不是原先的request了,但用起来与之前一样
print(request.method) # get print(request.path) # /books/ print(request.GET) # 原来的get请求提交的参数 print(request.POST) # 原来post请求提交的参数
-
Request的源码分析
查看 rest_framework.request.Request 导入后的源码
-
类中有个魔法方法: __ getattr__ 对象.属性,属性不存在会触发它的执行
def __getattr__(self, attr): # 如果取的属性不存在会去原生django的request对象中取出来 try: #反射:根据字符串获取属性或方法,self._request 是原来的request return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr)
-
以后用的所有属性或方法,直接用就可以了---》(通过反射去原来的request中取的)
-
新的request内部有个老的request,就是 request._request
-
data 是个方法,被property装饰了,变成了数据属性用
①以后body体中提交的数据,都从这里取(request.POST)
②urlencoded,form-data:提交的数据在request.POST中
③json格式提交的数据,在requets.POST中没有,它在request.body中
④现在无论那种格式,都从request.data中取
-
query_params
get请求提交的参数,等同于request._request.GET 或 request.GET
-
其他
取文件也是从request.FILES中取,跟之前一样
-
-
什么是魔法方法?
①在类中只要以__ 开头,__ 结尾的都称之为魔法方法
②这种方法不需要手动调用,某种情况会自动触发
③学过的魔法方法:
__ init__ , 类加括号 自动触发执行
__ str__ , 打印对象的时候触发执行
__ call__, 对象加括号的时候,自动触发执行
__ getattr__ 对象.属性,在属性不存在时会触发它的执行
-
总结
-
验证 原生requets.POST 只有urlencoded和form-data格式提交的数据,json格式提交的数据在body中,拿出来自己处理,但是drf的request中有个data,data中可以取到任意编码提交的数据
-
request.data 有时候是(urlencoded,form-data)QueryDict,有时候(json)是字典
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通