快速上手drf、CBV源码分析、APiview源码分析
一、快速上手drf
【1】安装drf
pip install djangorestframework
注意:
- 安装时不指定版本,默认下载最新版本
- 每个版本有对应的解释器版本和django限制要求,下载时官网查看一下
- 如果django版本是3以下,drf最新跟django3以下版本不兼容
版本要求:djangorestframework==3.12.4
Python (3.5, 3.6, 3.7, 3.8, 3.9)
Django (2.2, 3.0, 3.1)
版本要求:djangorestframework==3.11.2
Python (3.5, 3.6, 3.7, 3.8)
Django (1.11, 2.0, 2.1, 2.2, 3.0)
【2】配置,在settings.py中添加配置
INSTALLED_APPS = [
...
# 注册rest_framework(drf)
'rest_framework',
]
# drf相关配置以后编写在这里
REST_FRAMEWORK = {
}
【3】使用原生django实现5个接口
- 模型类 models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
- 配置路由(URL)
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view())
]
- 视图类 views
class BookView(View):
def get(self, request):
# 获取所有图书
book_list = models.Book.objects.all()
# Object of type QuerySet is not JSON serializable,json不能序列化queryset对象
return JsonResponse({"code": 100, "msg": "查询成功", "results": book_list})
# 新增图书
def post(self, request):
# 反序列化,把前端传的数据转为python
# request.body 是bytes格式,json格式不是字符串
data = json.loads(request.body)
book = models.Book.objects.create(**data)
return JsonResponse({"code": 100, "msg": "新增成功", "results": {"name": book.name, "price": book.price}})
class BookDetailView(View):
# 查单条
def get(self, request, pk):
book_obj = models.Book.objects.filter(pk=pk).first()
print(book_obj)
return JsonResponse(
{"code": 100, "msg": "查询成功", "results": {"name": book_obj.name, "price": book_obj.price}})
# 删除一条
def delete(self, request, pk):
book_obj = models.Book.objects.filter(pk=pk).first().delete()
if not book_obj:
return JsonResponse({"code": 101, "msg": "删除失败"})
return JsonResponse({"code": 100, "msg": "删除成功"})
# 修改
def put(self, request, pk):
models.Book.objects.filter(pk=pk).update(price=1000)
book_obj = models.Book.objects.filter(pk=pk).first()
if not book_obj:
return JsonResponse({"code": 101, "msg": "修改失败"})
return JsonResponse(
{"code": 100, "msg": "修改成功", "results": {"name": book_obj.name, "price": book_obj.price}})
补充:json可以序列化和反序列化的类型
+---------------+-------------------+
| JSON | Python |
+===============+===================+
| object | dict |
+---------------+-------------------+
| array | list |
+---------------+-------------------+
| string | str |
+---------------+-------------------+
| number (int) | int |
+---------------+-------------------+
| number (real) | float |
+---------------+-------------------+
| true | True |
+---------------+-------------------+
| false | False |
+---------------+-------------------+
| null | None |
+---------------+-------------------+
【4】使用drf实现5个接口
- 路由
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
]
urlpatterns += router.urls
- 视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
- 序列化类
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
二、CBV源码分析
【1】cbv写法:
- 视图中写视图类,继承View,写跟请求方式同名的方法
class BookView(View):
def get(self,request):
return 四件套
- 在路径用写
path('books/', BookView.as_view())
- 如上写法,为什么能够执行
【2】前置条件
- 前端请求,一旦路径匹配成功,就会执行
- BookView.as_view()(request传入,)
- 入口在
- BookView.as_view()--->执行结果---》View中有个as_view类的绑定方法
@classmethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
# 类实力化得到对象
# BookView类实例化得到对象
self = cls(**initkwargs)
# BookView类的dispatch
res=self.dispatch(request, *args, **kwargs)
return res
return view
- 执行结果是view 的内存地址: 请求来了,执行view(request)
path('books/', view)
- 执行 View类中的as_view方法中的内层的view函数,路由匹配成功,本质是在执行
self.dispatch(request, *args, **kwargs)
- self是谁的对象?
- BookView的对象
- 去BookView中dispatch,找不到
- 去父类,View中找到了
- View这个类的dispatch
def dispatch(self, request, *args, **kwargs):
# request.method.lower() 如果是get请求, ‘get’ 在这个列表里面
if request.method.lower() in self.http_method_names:
# handler=getattr(BookView的对象,'get')
# handler就是BookView类中的get方法
handler = getattr(self, request.method.lower())
else:
handler = self.http_method_not_allowed
# 执行 BookView类中的get方法 (request)
return handler(request, *args, **kwargs)
- 最终本质跟写fbv的执行流程一样
# 1 在路由中:path('index/',IndexView.as_view())
# 2 请求来了---》路由匹配成功--》执行 IndexView.as_view()(request)
-看View类的as_view的返回结果[可以加括号执行]---》猜:函数内存地址
# 3 View类的as_view
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls--》IndexView
return self.dispatch(request, *args, **kwargs)
return view
# 4 IndexView.as_view() 本质就是 --》view--》内存函数view
# 5 IndexView.as_view()(request)---》view(request)
# 6 本质 执行 self.dispatch--》self 是对象--》谁的对象?视图类的对象IndexView类的对象
return self.dispatch(request, *args, **kwargs)
# 7 IndexView没有dispatch--》View类中的dispatch
# request 当次请求的requets
def dispatch(self, request, *args, **kwargs):
#1 取出请求方式,转成小写,判断在不在列表中 get请求在
#2 self.http_method_names
if request.method.lower() in self.http_method_names:
# 3 反射:去 self IndexView类的对象中通过字符串get找属性或方法
# 找到了get方法,赋值给了handler
handler = getattr(self, request.method.lower())
else:
handler = self.http_method_not_allowed
# 4 执行handler--》本质是get(request)
# 执行了IndexView类中的get方法--》把request传进去了
return handler(request, *args, **kwargs)
# 8 总结:
路由匹配成功---》会根据请求方式执行视图类中跟请求方式同名的方法
三、APIView执行流程
drf中重写了 as_view
和dispatch
方法,其实就是在原来django的功能基础上添加了一些功能,例如:
-
as_view
,免除了csrf 验证,一般前后端分离不会使用csrf token认证(后期会使用jwt认证)。 -
dispatch
,内部添加了 版本处理、认证、权限、访问频率限制等诸多功能 -
以后只要继承APIView的所有视图类的方法,都没有csrf的校验了
-
以后只要继承APIView的所有视图类的方法 中的request是新的request了
-
在执行视图类的方法之前,执行了三大认证(认证,权限,频率)
-
期间除了各种错误,都会被异常捕获,统一处理
path('books/', views.BookView.as_view()),
# 1 请求来了---》会执行views.BookView.as_view()(request) ---》找as_view---》BookView找不到---》APIView中找---》as_view--->就干了一个事--》去除了csrf认证
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs) # 调用父类---》django原生View的as_view
view=csrf_exempt(view)
# 等同于
'''
@csrf_exempt
def view:
pass
'''
return view # 当前请求,去除掉了csrf认证
# 2 views.BookView.as_view()(request) 本质是执行 csrf_exempt(view)(request)
-执行View的 中as_view内的view函数--》去除了csrf认证
# 3 本质在执行:self.dispatch(request, *args, **kwargs)
BookView的dispatch---》BookView没有---》APIView找---》找到了
def dispatch(self, request, *args, **kwargs):
# 包装新的request
request = self.initialize_request(request, *args, **kwargs)
try:
# 执行三大认证
self.initial(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
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
# 总结:
1 APIView执行流程---》去除csrf--》执行了APIView的dispatch
2 执行的as_view是APIView的as_view
3 执行的dispatch也是APIView的dispatch
# 1 在路由中:path('books/', views.BookView.as_view()),请求来了
# 2 先看 as_view()---->APIView的 as_view---》as_view执行结果跟之前一样,去除了csrf认证
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs) # 调用父类的 as_view,view还是View的as_view
# 以后所有请求,都不会做csrf认证了
return csrf_exempt(view)
# 3 请求来了执行 views.BookView.as_view()(request)--->view(request)--->csrf_exempt(view)(request)--->内部核心---》return self.dispatch(request)
# 4 self 是 APIView类的对象---》APIView没有dispatch---》APIView的dispatch,核心代码如下
def dispatch(self, request, *args, **kwargs):
# 后续的request都是 initialize_request 返回结果--》新的request--》drf的Requet类的对象
request = self.initialize_request(request, *args, **kwargs)
# 新的request放到了 self.request中---》self是BookView类的对象
# 后续视图类的方法中 可以直接 self.request取出 当次请求的request对象
self.request = request
try:
# 执行了三大认证:
'''
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
'''
self.initial(request, *args, **kwargs)
###### 通过反射,去视图类中:BookView中执行跟请求方式同名的方法
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
# request是新的Request类的对象了 get方法的第一个参数request也是新的
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
# 5 看self.initialize_request 是APIView的
def initialize_request(self, request, *args, **kwargs):
# 类实例化得到对象,传入一些参数
# Request类--》drf提供的类
from rest_framework.request import Request
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# 只要继承APIView,以后方法中得request都变了,成了 rest_framework.request.Request 的对象了
但是用起来,跟之前的一模一样
# 原来的是:django.core.handlers.wsgi.WSGIRequest 类的对象
# 总结:
1 以后视图类方法中得request对象,变成了新的request,它是rest_framework.request.Request 的对象了,但是用起来跟之前一样
2 把新的request对象,同时放到了 视图类的对象中 self.request = request 后续从视图类中可以直接通过 self.request取出来
3 在执行视图类的方法之前,执行了三大认证
4 如果三大认证或视图类的方法执行出错,会有全局异常处理
5 以后所有的接口都去除了csrf认证
补充:装饰器原理
import time
def add(a, b):
time.sleep(1)
return a + b
#### 统计add的运行时间
# start_time = time.time()
# add(3, 4)
# end_time = time.time()
# print('运行时间是:', end_time - start_time)
### 写一个通用的,以后只要统计任意函数运行时间,都使用通用的--->改变了调用方式,不行
# def outer(func):
# start_time = time.time()
# func(3, 4)
# end_time = time.time()
# print('运行时间是:', end_time - start_time)
#
# outer(add)
def outer(func):
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print('运行时间是:', end_time - start_time)
return res
return inner
# inner=outer(add)
# 调用inner,就是执行,inner内部包了 add函数,inner叫闭包函数
# inner() # 改变了调用方式
# 继续优化
add = outer(add)
res = add(3, 4) # add现在本质调用 inner,参数传给 inner,inner要能接收a,b 并且有返回结果
print(res)
# 以后想装饰哪个函数 得按如下操作,麻烦
# def ee():
# print('ee')
#
# ee=outer(ee)
# ee()
# python提供了一个语法糖 @ ,以后只要按如下方式编写代码,就能实现上述功能
@outer # 等同于 ee=outer(ee) 该语法糖会把被装饰器的函数ee,当做参数,传入outer,并且把outer的执行结果,返回赋值给ee
def ee():
print('ee')
# 以后ee其实已经不是ee了,是inner了,执行ee本质在执行inner
#####上述是原理####
## 记忆
# 以后写它
def outer(func):
def inner(*args, **kwargs):
# 被装饰器函数,执行之前干事
res = func(*args, **kwargs)
#被装饰函数,执行之后干事情
return res
return inner
# 装饰某个函数
@outer
def add(a,b):
time.sleep(1)
return a+b
标签:02,return,APIVIEW,self,request,源码,time,def,view
From: https://www.cnblogs.com/Formerly/p/18194203