想学好django框架–drf就必须先进行CBV的源码解读
CBV(class base views) 基于类的视图,就是在视图里使用类处理请求。
当路由匹配到如上user的时候,执行其后面的views.UserView中的as_view方法。
urls.py 文件
urlpatterns = [
path("users/", views.Userview.as_view()),
]
views.py 文件
from rest_framework.views import APIView
class UserView(APIView):
pass
我们可以看到在我们自己写的类UserView中并没有as_view方法,但它继承于APIView,我们可以在1中看到,APIView的as_view继承了父类View(也就是CBV模式下最先学习的基类)的全部功能,此时我们获得了原本的view函数。在1的retrun中我们看到了csrf_exempt(view),这一步的过程其实就像我们以前去掉csrf_token认证引入的装饰器一样,用于去除csrf_token认证。我们以后选择用jwt进行认证。
主要还是通过父类 View 提供的一个静态方法 as_view() ,as_view 方法是基于类的外部接口, 他返回一个视图函数,调用后请求会传递给 dispatch 方法,dispatch 方法再根据不同请求来处理不同的方法。
@classonlymethod
def as_view(cls, **initkwargs):
..........
def view(request, *args, **kwargs):
...........
return self.dispatch(request, *args, **kwargs) #关键这句
.........
return view
def dispatch(self, request, *args, **kwargs):
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
return handler(request, *args, **kwargs)
以上是django的View的as_view方法 所以以上使用getattr函数用来获取一个对象的属性值或方法
进入drf框架的site-packages\rest_framework\views.py文件下
class APIView(View):
.....
我们与View基类的dispatch做对比,看到它除了与基类同样运用反射获取请求方式外,其前后还分别对request和response进行了封装。
drf中重写了 as_view 和dispatch方法,其实就是在原来django的功能基础上添加了一些功能
例如:
as_view,免除了csrf 验证,一般前后端分离不会使用csrf token认证(后期会使用jwt认证)。dispatch,内部添加了 版本处理、认证、权限、访问频率限制等诸多功能(后期逐一讲解)。
Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
django开发项目时,视图中的request是 django.core.handlers.wsgi.WSGIRequest 类的对象
# Django FBV
def index(request):
request.method
request.POST
request.GET
request.body
# Django CBV
from django.views import View
class UserView(View):
def get(self,request):
request.method
request.POST
request.GET
request.body
在使用drf框架时,视图中的request是rest_framework.request.Request类的对象,其是又对django的request进行了一次封装,包含了除django原request对象以外,还包含其他后期会使用的其他对象。
from rest_framework.views import APIView
from rest_framework.response import Response
class UserView(APIView):
def get(self, request, *args, **kwargs):
return Response({"code": 1000, "data": "xxx"})
def post(self, request, *args, **kwargs):
return Response({"code": 1000, "data": "xxx"})
注:此时你看到的request,不再是曾经django中的request,而是又被封装了一层,内部包含:django的request、认证、解析器等。
在源码3中,大概是这样:有一个rest_framework.request.Request
类,我们最后获得的request=Request(request,认证,分页…)
在文件site-packages\rest_framework\request.py中Request类
class Request:
......
我们从源码中可以看到,想要从请求中获取数据,有两种方法:
第一种:
request._request.method
request._request.GET
request._request.POST
request._request.body
第二种:
# 直接读取新request对象中的值,一般此处会对原始的数据进行一些处理,方便开发者在视图中使用。
request.query_params # 内部本质上就是 request._request.GET
# 内部读取请求体中的数据,并进行处理,例如:请求者发来JSON格式,他的内部会对json字符串进行反序列化。
request.data
# 通过 __getattr__ 去访问 request._request 中的值
request.method
request.method这样的可以通过反射获取,因此不需要改变。这里我们用request.query_params 替换了request.GET,request.data替换了request.POST.
值得一提的是,request.data会对收到的json格式自动进行反序列化。此外无论是content-type:
url-form-encoded还是content-type: application/json,该方法都可以获取到内容。
RESTful是一种定义Web API接口的设计风格,尤其适用于前后端分离的应用模式中。
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。
事实上,我们可以使用任何一个框架都可以实现符合restful规范的API接口。
url链接一般都采用https协议进行传输
注:采用https协议,可以提高数据交互过程中的安全性
用api关键字标识接口url:
https://api.baidu.com
https://www.baidu.com/api
注:看到api字眼,就代表该请求url链接是完成前后台数据交互的
在url链接中标识数据版本
https://api.baidu.com/v1
https://api.baidu.com/v2
注:url链接中的v1、v2就是不同数据版本的体现(只有在一种数据资源有多版本情况下)
接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
https://api.baidu.com/users
https://api.baidu.com/books
https://api.baidu.com/book
注:一般提倡用资源的复数形式,在url链接中奖励不要出现操作资源的动词,错误示范:
https://api.baidu.com/delete-user
特殊的接口可以出现动词,因为这些接口一般没有一个明确的资源,或是动词就是接口的核心含义
https://api.baidu.com/place/search
https://api.baidu.com/login
操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查动作
https://api.baidu.com/books - get请求:获取所有书
https://api.baidu.com/books/1 - get请求:获取主键为1的书
https://api.baidu.com/books - post请求:新增一本书书
https://api.baidu.com/books/1 - put请求:整体修改主键为1的书
https://api.baidu.com/books/1 - patch请求:局部修改主键为1的书
https://api.baidu.com/books/1 - delete请求:删除主键为1的书
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:指定筛选条件
响应状态码2xx
200:常规请求
201:创建成功
响应状态码3xx
301:永久重定向
302:暂时重定向
响应状态码4xx
403:请求无权限
404:请求路径不存在
405:请求方法不存在
响应状态码5xx
500:服务器异常
{
error: "无权限操作"
}
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
# Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(罗餐厅)",
"img": "https://image.baidu.com/kfc/001.png"
}
...
]
}
比较好的接口返回
# 响应数据要有状态码、状态信息以及数据本身
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(罗餐厅)",
"location":{
"lat":31.415354,
"lng":121.357339
},
"address":"月罗路2380号",
"province":"上海市",
"city":"上海市",
"area":"宝山区",
"street_id":"339ed41ae1d6dc320a5cb37c",
"telephone":"(021)56761006",
"detail":1,
"uid":"339ed41ae1d6dc320a5cb37c"
}
...
]
}