• 24 DRF详细学习篇章一|Requests|Responses|View|Routers


    快速入门你可能搞混的知识

    重写preform_ 与重写save

    在这里插入图片描述

    回想一下我们之前什么时候用到了这两个?

    关于前者,我们重写了preform_create这个方法(在view当中),我们的目的是,在运行的时候自动获取账户的名称,然后加入我们的json当中传回数据,并保存到数据库当中,所以我们使用了preform_create也就是为了在真正的POST请求到来,你传入的数据多这么一个,这个流程是先于后者的save的。

    而对于save来说,我们是得到了前端传回的所有数据(包括那个owner)之后,我们要进行存入数据,如果不写就直接进行存储,如果重写这个函数,就可以先进行数据分析,然后再存入数据,整个流程是这样子的。

    这二者的关键理解在于是否理解好ORM,依赖倒置原则的处理流程,根据不同情况选择不同的函数进行重写,就是面向切片变成的重要思想,了解切片变成重点了解的就是其运行的流程图。

    Requests 请求

    源代码位于:request.py

    对于DRF的request对象,有下面的主要属性:

    1. .data
    2. .query_params
    3. .parsers
    4. .accepted_renderer
    5. .accepted_media_type
    6. .user
    7. .auth
    8. .authenticators
    9. .method
    10. .content_type
    11. .stream

    后面我们会对这些进行一一介绍,并且标注重要星级:

    重要程度分级:

    1. 不重要:(⭐)
    2. 了解:(⭐⭐)
    3. 重点了解(⭐⭐⭐)

    原本的Django的request (⭐)

    在这里插入图片描述
    我们到:使用了request的create当中进行调试:
    在这里插入图片描述
    然后前端随便传入一个数据上去:
    在这里插入图片描述
    然后在调试窗口可以进行查看,稍微玩个花火,实际上drf框架的request实际上已经将Django的request中的内容进行调到了自己的内部了,也没太必要去看这一步,除非你是修改框架的人士。OwO

    .data (⭐⭐⭐)

    .data:提交的数据都在data当中,比较类似的是request.post

    先给出我刚刚提交的data:
    在这里插入图片描述
    调试窗口,可以看到内部数据都在这里:
    在这里插入图片描述
    request.data 返回请求正文的分析内容。这与标准 request.POST 和request.FILES 属性类似,不同之处在于:

    1. 它包括所有解析的内容,包括文件和非文件输入。
    2. 它支持解析 POST HTTP 方法的内容,这意味着您可以访问 和 PATCH 请求PUT 的内容。
    3. 它支持 REST 框架的灵活请求解析,而不仅仅是支持表单数据。例如,您可以像处理传入表单数据一样处理传入的 JSON 数据。

    .query_params (⭐⭐⭐)

    request.query_params 是 的 request.GET 更正确命名的同义词,实际上他内部的参数是浏览器上方的?page=2,这种类型的参数

    这边用换页进行展示:
    因为类似的是Get,所以我们这边选择到list进行查看(你也可以到RetrieveModelMixin进行查看)。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    如此自然可以看到这个参数代表的含义。

    .parsers (⭐)

    APIView 类或 @api_view 装饰器将根据view中设置的 parser_classes 值或DEFAULT_PARSER_CLASSES 配置参数进行设置,确保此属性自动设置为Parser 实例列表。通常并不需要访问这个属性。

    在这里插入图片描述
    实际上这三个就是解析器,是按照这三个的顺序分别进行解析数据的,比如我们在浏览器中的末尾加上.json,那么就会按照json的格式传递给我们数据,原因就是在这里调用了JSONParser 渲染器,html同理。

    注意:如果客户端发送格式不正确的内容,则访问 request.data 可能会引发ParseError .默认情况下, APIView REST 框架的类或 @api_view 装饰器将捕获错误并返回 400 Bad Request 响应。

    解析器(media type),实际上就是传入数据的格式,比如你选择了json,那么他就会按照json的格式去识别你的content,并解析,然后再传到data当中:
    在这里插入图片描述

    .accepted_renderer (⭐⭐)

    内容协商阶段选择的呈现器实例。

    在这里插入图片描述

    .accepted_media_type (⭐⭐)

    在这里插入图片描述
    这个就是我们返回的数据是什么格式的,现在我们返回的不都是json的数据,也就是都是字符串,后续也可能包括图片什么的,这边就会进行改变

    .user (⭐⭐⭐)

    顾名思义,也就是显示你当前登录的账户的user,一般是需要利用这个user做身份验证。
    在这里插入图片描述
    如果请求未经身份验证,则默认值为 :

    request.user = django.contrib.auth.models.AnonymousUser
    
    • 1

    .auth (⭐⭐⭐)

    这边只进行展示,虽然很重要,但详情的介绍等待之后,进行揭晓:

    request.auth 返回任何其他身份验证上下文。的确切行为取决于所使用的身份验证策略,但它通常可能是请求所针对的令牌的 request.auth 实例。

    如果请求未经身份验证,或者不存在其他上下文,则缺省 request.auth 值为 None 。

    在这里插入图片描述

    .authenticators (⭐)

    返回的就是验证身份的方法,这一部分也到后面再进行讲解:

    在这里插入图片描述
    值得关注的是这边出现了Session,学过Django的我们自然懂得相关的属性含义

    APIView 类或修饰器将确保此属性根据视图上的 authentication_classes 设置或 @api_view 基于 DEFAULT_AUTHENTICATORS 设置自动设置为实例列表 Authentication 。

    通常不需要访问此属性

    .method (⭐⭐⭐)

    request.method 返回请求的 HTTP 方法的大写字符串表示形式。

    这边就不进行演示了,如果想看这个method的方法,就不能再我们刚刚那个打的断点的位置进行查看,需要到上一级,也就是到request.py里面进行打断点进行查看,这边大家肯定懂这个的意思,这边就不详细说明OvO,懒~~

    不过很重要哈

    .content_type (⭐)

    在这里插入图片描述
    返回一个字符串对象,表示 HTTP 请求正文的媒体类型,如果未提供媒体类型,则返回空字符串,一般不使用。

    .stream (⭐)

    在这里插入图片描述
    request.stream 返回表示请求正文内容的流。

    一般不使用。

    Responses

    这一块其实不是很重要,就不带领大家一步步调试理解了,这边就列几个常见的,可能常用的进行了解

    如下表建立起来,但是一般来说前两个记忆一下即可。

    参数说明
    data响应的序列化数据,或者说就是后端要传给前端的数据
    status响应的状态代码。默认值为 200。
    template_name选择 HTMLRenderer 时要使用的模板名称。
    headers要在响应中使用的 HTTP 标头的字典。
    content_type响应的内容类型。通常,这将由呈现器根据内容协商确定自动设置,但在某些情况下可能需要显式指定内容类型。

    View

    还是这张图,很重要哈:
    在这里插入图片描述
    经过了快速入门之后,这边再进行系统的介绍一遍方便查缺补漏,进行理解:

    APIView、MinixView、GenericAPIView

    这三个类就进行跳过了,详情见我的快速入门
    链接

    Minix具体的通用类视图

    说明
    CreateAPIView仅用于创建功能的视图,只提供post方法
    ListAPIView以只读的方式列出某些查询对象的集合。提供list方法
    RetrieveAPIView以只读的形式获取某个对象。提供get 方法
    DestroyAPIView删除单个模型实例。提供delete方法。
    UpdateAPIView更新单个模型实例。提供 put和 patch方法。
    ListCreateAPIView创建或者列出模型实例的集合。提供get和list方法。同时继承了ListModelMixin和CreateModelMixin两个mixin类,以及基类 GenericAPIView。
    RetrieveUpdateAPIView读取或更新单个模型实例。提供get和 put 和patch方法
    RetrieveDestroyAPIView读取或删除单个模型实例。提供get和 delete方法。
    RetrieveUpdateDestroyAPIView读写删除单个模型实例。提供 get, put, patch和delete方法

    ModelViewSets

    这边进行回想一下,在GenericAPIView下我们view的代码是不是已经写好了正常的list页面和detail页面,而我们这里的ModelView就是基于那一个的基础上进行增加的,或者这么说,我们前面展示的页面都是对于(/user/ 或者 /user/1/),但此时我们想要更加多的页面的时候,该怎么办?

    最基础的形态:

    class UserViewSet(viewsets.ModelViewSet):
        """
        A viewset for viewing and editing user instances.
        """
        serializer_class = UserSerializer
        queryset = User.objects.all()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    urls:

    from myapp.views import UserViewSet
    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    router.register(r'users', UserViewSet, basename='user')
    urlpatterns = router.urls
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这个最基础的效果之下,我们的基础的list 和 detail页面的get post put delete等一系列操作就已经写好了,但此时我们想像快速入门一样,在原本的url的基础上进行添加新的页面,此时就需要引入action的装饰器操作。

    下面先介绍ModelViewSet下的一些基础属性(不是很重要,了解即可):

    属性说明
    basename根url路径
    action当前操作的名称(例如, list 、 create )。
    detail布尔值,指示当前操作是否配置为列表或详细信息视图。
    suffixviewset类型的前缀
    nameviewset的名字
    description视图集的单个视图的显示说明

    为了方便展示,这边把代码修改成这样子:

    class UserViewSet(viewsets.ReadOnlyModelViewSet):
        """
        This viewset automatically provides `list` and `retrieve` actions.
        """
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
        @action(detail=False, methods=['get'])
        def A(self, request):
            return Response({'status': 'A'})
    
        @action(detail=True, methods=['get', 'post'])
        def B(self, request, pk):
            return Response({'status': 'B'})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    把断点打在A函数的return上,然后访问http://127.0.0.1:8000/users/A/

    此时就可以看出action实际上就是访问的网页的页名,或者说是函数的名称:
    在这里插入图片描述
    basename就是类名,或者说是
    在这里插入图片描述
    在这里插入图片描述
    也等价于:
    在这里插入图片描述
    detail:判断是list的子页面还是detail的子页面
    在这里插入图片描述
    suffix就是后缀,这边没有显示,或者可以说就是那个html
    在这里插入图片描述

    name
    是一整个名字,比如这边就是A
    在这里插入图片描述

    创建新的页面

    在这里插入图片描述
    当然还有一些特定化的操作:

    修饰器允许您覆盖任何视图集级别的配置,例如 permission_classes 、、 serializer_class filter_backends ...@action(detail=True, methods=['post'], permission_classes=[IsAdminOrIsSelf])
        def set_password(self, request, pk=None):
           ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    路由其他 HTTP 方法以进行额外操作

    额外的操作可以将其他 HTTP 方法映射到单独的 ViewSet 方法。例如,上述密码设置/取消设置方法可以合并为单个路由。请注意,其他映射不接受参数。

    	# name=“change password”只是修改名字,并不是修改访问的url,此时还是需要使用password进行访问的
        @action(detail=True, methods=['put'], name='Change Password')
        def password(self, request, pk=None):
            """Update the user's password."""
            ...
    
        @password.mapping.delete
        def delete_password(self, request, pk=None):
            """Delete the user's password."""
            ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    换到html当中就是其的title

    获取url

    如果需要获取操作的 URL,请使用该方法 .reverse_action() 。这是一个方便的包装器 reverse() ,会自动传递视图 request 的对象并在 前面 url_name 加上 .basename 属性。

    请注意,路由器在注册期间 ViewSet 提供。 basename 如果不使用路由器,则必须为 .as_view() 该方法提供 basename 参数。

    >>> view.reverse_action('set-password', args=['1'])
    'http://localhost:8000/api/users/1/set_password'
    
    • 1
    • 2

    Routers

    常见的Router函数:

    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    from snippets import views
    
    # 路由器
    # Create a router and register our viewsets with it.
    router = DefaultRouter()
    router.register(r'snippets', views.SnippetViewSet, basename="snippet")
    router.register(r'users', views.UserViewSet, basename="user")
    
    # The API URLs are now determined automatically by the router.
    urlpatterns = [
        path('', include(router.urls)),
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    常见参数的含义

    该方法 register() 可接收下面的几个常用的参数:

    参数说明
    prefix用于这组路由的 URL 前缀,比如这边就是‘’空,实际上访问的话,就是由路由器自动生成‘’+你对应的类名加后续
    viewset视图集类。
    basename用于创建的 URL 名称的基础。如果未设置,将根据视图集 queryset 的属性自动生成基本名称(如果有)。请注意,如果视图集不包含 queryset 属性,则必须在注册视图集时进行设置 basename 。

    关于include

    urlpatterns = [
        path('forgot-password/', ForgotPasswordFormView.as_view()),
        path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
    ]
    
    • 1
    • 2
    • 3
    • 4

    又出现两个参数:

    参数说明
    app_name这个是为了避免由于一个项目拥有多个app,这边就需要添加上对应的app_name,可以随便取名,但是后面在调用包含在这个app的对应的方法的时候,就需要使用app_name:view_name ,下面会给个例子
    namespace这个一般用于版本控制,这个后面再提

    DefaultRouter 默认路由器

    默认路由包括一个默认的 API 根视图,该视图返回包含指向所有列表视图的超链接的响应。它还为可选的 .json 样式格式后缀生成路由,一般直接使用这个即可,其他的自定义类型的就不定义了。

    在这里插入图片描述

  • 相关阅读:
    Eureka原理实践
    MySQL 类型和 Java 类型对应关系
    C++ - AVL 树 介绍 和 实现 (上篇)
    JavaScript基础知识——练习巩固(2)
    Python time模块获得当前时间
    国庆假期买哪款耳机好?国庆假期必备蓝牙耳机推荐
    【华为上机考试真题】汽水瓶
    Windows版MySql8.0安装(亲测成功!)
    【分布式系统】业务拆分后数据库将面临什么问题
    nginx绑定tomcat与tomcat联合使用的配置(nginx反向代理tomcat的配置说明)
  • 原文地址:https://blog.csdn.net/Micoreal/article/details/132966756