django_rest_framework
Django-rest-framework
01-FBV和CBV

FBV: function based view


CBV: class based view

# views.py
from django.shortcuts import render, HttpResponse
from django.views import View
class LoginView(View):
def get(self,request):
return HttpResponse("LoginView Get...")
def post(self, request):
return HttpResponse("LoginView POST..")
02-面向对象补充

类和实例对象, 一切皆对象, 类有自己的一块存储空间, 实例对象也有自己的一块存储空间
实例变量存放在自己的空间中, 类变量也存储在自己的空间中, 如果 实例变量中没有,则向类中去找,如果 创建实例的类中也没有相关的变量, 那么向父类中去找, 如果所有的 父类中都没有找到,那么会报错。
类属性,公共的属性, 例如一个班级的类,所有的学校是一样的,班级名称不一样 (实例属性)


上面的 alex.name = "alex" 相当于在 "alex"() 字符串 后面加了个括号,字符串不可调用错误。

上图:25行 实例化了一个对象, 开辟一块新的内容空间, 调用创建类的__init__方法,创建类没有,
调用父类的 __init__方法 name= name, age = age, __init__方法中调用了 self.foo(), 方法, 先去对象的创建类中找, 创建类中有一个 foo 变量, 和一个 foo 方法, foo 方法在后面, 所以,最终调用的是创建类的 foo 方法, 打印 A foo

上图:25行 实例化了一个对象, 开辟一块新的内容空间, 调用创建类的__init__方法,创建类没有,
调用父类的 __init__方法 name= name, age = age, __init__方法中调用了 self.foo(), 方法, 先去对象的创建类中找, 创建类中有一个 foo 变量, 和一个 foo 方法, foo 变量在后面, foo 代表的是 foo 变量 是一个 100 的整数, 调用 100() 报错, 'int' object is not callable

上图, 加载类的时候,设置变量 name = "xxx", foo= 100 (foo 变量指向 100 数值所在的空间)
然后定义 foo 方法, foo 指向一个方法名, 不再指向 100 了, 所有 foo 是可以调用的。
03-cbv 源码解析
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import LoginView
urlpatterns = [
path('admin/', admin.site.urls),
path("login/", LoginView.as_view())
]
app/views.py
from django.shortcuts import render, HttpResponse
from django.views import View
# Create your views here.
class LoginView(View):
def get(self, request):
return HttpResponse("LoginView get")
def post(self, request):
return HttpResponse("LoginView post")
请求 request 访问相关的 url ,调用cbv 中的类, 根据请求方法的不同,走不同的函数。
加载 url.py 时,就加载了
path("login/", LoginView.as_view()) 中的 LoginView.as_view()
# LoginView 类中没有 as_view() 方法, 向父级去找, View 类中有 as_view 方法
View 类中的 as_view 方法
# @classonlymethod 装饰器装饰的函数只能由类对象调用,
# @classmethod 装饰器装饰的函数 实例对象也可以调用。
@classonlymethod
# cls 是 loginView 类对象
# 涉及到闭包,一个函数内部有另一个函数,变量在 内部函数中被引用,外部函数执行完,不会销毁变量,为内部函数保存变量
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(
"The method name %s is not accepted as a keyword argument "
"to %s()." % (key, cls.__name__)
)
if not hasattr(cls, key):
raise TypeError(
"%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key)
)
def view(request, *args, **kwargs):
# 下面的 self 是 LoginView 对象的一个实例对象
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
if not hasattr(self, "request"):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
# dispatch 分发 去 LoginView 找dispath 方法, 没有找到, 去父类view 中找
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# __name__ and __qualname__ are intentionally left unchanged as
# view_class should be used to robustly determine the name of the view
# instead.
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.__annotations__ = cls.dispatch.__annotations__
# Copy possible attributes set by decorators, e.g. @csrf_exempt, from
# the dispatch method.
view.__dict__.update(cls.dispatch.__dict__)
# Mark the callback if the view class is async.
if cls.view_is_async:
markcoroutinefunction(view)
return view
View 中的 dispatch 方法、
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
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
# 调用 CBV 相关请求方式的视图函数,
# 如果请求方式是get 的话相当于 LoginView 下的 get(request, *args, **kwargs)
return handler(request, *args, **kwargs)


反射


添加一些公共的功能
写一个自己的 dispatch 方法, 就会调用自己的,在自己的 dispatch 中 引用父类的方法。添加一些自己需要的功能。

04-前后端分离模式
使用 django 的ORM 从数据库查询出来的数据类型是一个queryset, 而queryset 是 python 的一种特殊的数据类型,如果是前后端分离的项目,前端无法识别这种类型, 可以使用 序列化操作,将queryset 对象 转化成 Json 对象(序列化), 可以将将 Json 对象转换成 queryset 对象(反序列化)。
安装组件 drf(django-rest-framework)
# pip install django-rest-framework -i https://mirrors.aliyun.com/pypi/simple/





















使用drf 创建一个 资源的 增, 删, 改, 查所有, 查单个(5 个接口)
创建需要的模型类

创建 CBV的 url 和视图类的映射关系

django-rest-framework 中的 序列化器 和 视图类
05-drf 中的 APIView
drf APIView 是在 django 的 View 的基础上做了继承和扩展。

APIView 类中重写了 View 中的 dispatch 方法

# APIView 中的 dispatch 方法
# 重构了 request 对象, 对json 数据和 路径传参的参数做了一些处理,post 请求数据封装到 request.data 中, get请求封装到了 request.query_params 中, 原来的 request.GET 也保留着。
# self.initial(request, *args, **kwargs) 中有三个组件,分别和认证, 权限, 和限流有关。
# 后面 和 django 中的view 一样的是 利用反射实现 根据请求方式的不同,的路由分发。
# APIView 中的 dispatch 方法
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 重构了 request 对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 这里有三个小组件
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
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
# self.initial 中有三个组件
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
# 认证 有关组件
self.perform_authentication(request)
# 权限 有关组件
self.check_permissions(request)
# 限流 有关组件
self.check_throttles(request)

06-序列化组件




使用 rest_framework.response 中的Response 返回的是 Json 字符串


可以在序列化行的 参数中写 source="name" 指明 和models中的哪个字段相对应, 如果不写和 序列器的字段名对应,写source 的话, 序列化器的字段名就可以修改自己想要的值了。

序列化单个数据库中的字段信息 和 id 字段有关, 写一个新的url , 一个新的 视图类,接收id 参数,对某个单独的数据进行操作。
调用写好的序列化类时,many 参数 设置为 False


post请求, 提交数据, 提交数据的时候需要做数据校验, django drf 中的序列化组件提供了 数据校验的功能, 使用方法如下
将 post 提交的数据 request.data 传递给 序列化器的data 字段, 数据字段的校验规则,首先利用序列化组件中的字段类型进行校验
类似于 django 中的 forms 组件的校验

返回的内容,get 查询所有, 返回查询的所有信息, post 添加,返回添加的内容,
get 一条数据, 返回 查询到的一条数据, delete 删除信息, 返回 空, put 请求方式 更新操作,返回更新后的内容。(规范)

删除 /books/1 url delete 方法

更新 /books/1 put 方法

07-视图mixin类



08-DRF快速实例演示











09-APIVIew视图函数的添加和查看







第二部分



10-API视图的ModelSerializser




11-GenericAPIView的调用方法






12-Minin混合类接口实现




13.视图类二合一面临的问题
两个视图类, 一个视图类中 的get 方法是 查询所有 资源, 一个视图类中的 get 方法是查询单个资源


14.modelViewSet的接口实现

两个视图类合并成一个视图类

如下图所示同一个视图类,给请求方式指定 调用的方法名, 所有资源的 get 请求方式, 访问 视图类中的 list 方法, 单一资源的 get 请求方式,访问视图类中的 single 方法


视图类继承 ViewSetMixin 类, 可以在 url 对应的视图类中自定义 请求方式对应的 视图类中的方法。(路由分发机制的改变)


viewSet 源码分析 urls.py 中 url 和 视图类的映射中, 视图类中的 as_view 方法, 调用的是 ViewSetMinxin 中的 as_view 方法
这个 as_view 方法接收一个 aciton 参数(字典类型),循环设置每种请求方式对应的视图类中的方法, 然后 调用 APIView 中 的 dispath 方法做路由的分发。


将 业务逻辑的封装和 路由分发的合并的类结合在一起,视图类中 的请求方式 应该和 封装好的类中 的 方法对应
下面的代码 将 多个类的继承关系封装在了 一个新的类中 ModelViewSet 中

15反序列化校验字段的补充


浙公网安备 33010602011771号