django_rest_framework

Django-rest-framework

01-FBV和CBV

image-20250706122704537

FBV: function based view

image-20250706123545945

image-20250706123138803

CBV: class based view

image-20250706123924367

# 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-面向对象补充

image-20250706125634815

类和实例对象, 一切皆对象, 类有自己的一块存储空间, 实例对象也有自己的一块存储空间

实例变量存放在自己的空间中, 类变量也存储在自己的空间中, 如果 实例变量中没有,则向类中去找,如果 创建实例的类中也没有相关的变量, 那么向父类中去找, 如果所有的 父类中都没有找到,那么会报错。

类属性,公共的属性, 例如一个班级的类,所有的学校是一样的,班级名称不一样 (实例属性)

image-20250706130350091

image-20250706130856089

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

image-20250706131219078

上图:25行 实例化了一个对象, 开辟一块新的内容空间, 调用创建类的__init__方法,创建类没有,

调用父类的 __init__方法 name= name, age = age, __init__方法中调用了 self.foo(), 方法, 先去对象的创建类中找, 创建类中有一个 foo 变量, 和一个 foo 方法, foo 方法在后面, 所以,最终调用的是创建类的 foo 方法, 打印 A foo

image-20250706132013551

上图:25行 实例化了一个对象, 开辟一块新的内容空间, 调用创建类的__init__方法,创建类没有,

调用父类的 __init__方法 name= name, age = age, __init__方法中调用了 self.foo(), 方法, 先去对象的创建类中找, 创建类中有一个 foo 变量, 和一个 foo 方法, foo 变量在后面, foo 代表的是 foo 变量 是一个 100 的整数, 调用 100() 报错, 'int' object is not callable

image-20250706132949327

上图, 加载类的时候,设置变量 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)

image-20250706140952298

image-20250706141112155

反射

image-20250706142213428

image-20250706142437114

添加一些公共的功能

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

image-20250706143449029

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/

image-20250706172706176

image-20250706172805726

image-20250706173009919

image-20250706173155419

image-20250706173457131

image-20250706173609822

image-20250706173711157

image-20250706173739428

image-20250706173846424

image-20250706175018836

image-20250706175519675

image-20250706175749025

image-20250706175804048

image-20250706175823536

image-20250706175849017

image-20250706180226760

image-20250706180400158

image-20250706180430782

image-20250706180509770

image-20250706180722756

image-20250706181323697

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

创建需要的模型类

image-20250706181747628

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

image-20250706181851318

django-rest-framework 中的 序列化器 和 视图类

05-drf 中的 APIView

drf APIView 是在 django 的 View 的基础上做了继承和扩展。

image-20250706182618332

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

image-20250706191427166

# 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)

image-20250706213616982

06-序列化组件

image-20250706213848126

image-20250706214736740

image-20250706214900085

image-20250706215258731

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

image-20250706215746199

image-20250706215833641

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

image-20250706220102872

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

调用写好的序列化类时,many 参数 设置为 False

image-20250709073004293

image-20250709073230428

post请求, 提交数据, 提交数据的时候需要做数据校验, django drf 中的序列化组件提供了 数据校验的功能, 使用方法如下

将 post 提交的数据 request.data 传递给 序列化器的data 字段, 数据字段的校验规则,首先利用序列化组件中的字段类型进行校验

类似于 django 中的 forms 组件的校验

image-20250709075738567

返回的内容,get 查询所有, 返回查询的所有信息, post 添加,返回添加的内容,

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

image-20250709075416171

删除 /books/1 url delete 方法

image-20250709201519701

更新 /books/1 put 方法

image-20250709202139575

07-视图mixin类

image-20250709204102765

image-20250709204449566

image-20250709204555273

08-DRF快速实例演示

image-20250709205545862

image-20250709210718814

image-20250709210741808

image-20250709210831401

image-20250709210914722

image-20250709211003372

image-20250709211121412

image-20250709211205407

image-20250709211309464

image-20250709211405481

image-20250709211533250

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

image-20250709212350646

image-20250709212406248

image-20250709212619027

image-20250709213303187

image-20250709213844709

image-20250709213938722

image-20250709214241481

第二部分

image-20250709214428538

image-20250709215021364

image-20250709215253784

10-API视图的ModelSerializser

image-20250709221609247

image-20250709220523290

image-20250709220918773

image-20250709221916286

11-GenericAPIView的调用方法

image-20250710074112536

image-20250710075304701

image-20250710075754444

image-20250710080436126

image-20250710080335337

image-20250710080541839

12-Minin混合类接口实现

image-20250712102050733

image-20250712102159776

image-20250712102405522

image-20250712102939781

13.视图类二合一面临的问题

两个视图类, 一个视图类中 的get 方法是 查询所有 资源, 一个视图类中的 get 方法是查询单个资源

image-20250712103758955

image-20250712103917550

14.modelViewSet的接口实现

image-20250712104335676

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

image-20250712104442396

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

image-20250712104655588

image-20250712105020103

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

image-20250712105133664

image-20250712105522708

viewSet 源码分析 urls.py 中 url 和 视图类的映射中, 视图类中的 as_view 方法, 调用的是 ViewSetMinxin 中的 as_view 方法

这个 as_view 方法接收一个 aciton 参数(字典类型),循环设置每种请求方式对应的视图类中的方法, 然后 调用 APIView 中 的 dispath 方法做路由的分发。

image-20250712110825644

image-20250712111354851

将 业务逻辑的封装和 路由分发的合并的类结合在一起,视图类中 的请求方式 应该和 封装好的类中 的 方法对应

下面的代码 将 多个类的继承关系封装在了 一个新的类中 ModelViewSet 中

image-20250712112400664

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

image-20250712113337232

posted @ 2025-07-12 13:08  Ref-brief  阅读(24)  评论(6)    收藏  举报