DRF(Django Rest Framework)框架基于restAPI协议规范的知识点总结

Django Rest Framework学习

一、初识DRF组件

1.1 FBV和CBV
  • FBV:function based view

    python 复制代码
    from django.shortcuts import render, HttpResponse
    # 这种是基于FBV模式  函数模式实现Views函数
    def login(request):
        if request.method == 'GET':
            return HttpResponse("Get请求。。。。")
        return HttpResponse("POST请求。。。。")

    在FBV下调函数不加(),例如path('login/', views.Login)url是映射,指向这块空间

  • CBV:class based view

    1.app目录下的views.py下

    python 复制代码
    from django.shortcuts import render, HttpResponse
    from django.views import View
    # 类要继承django的view模块
    class LoginView(View):
        # 这个函数是固定写法,必须叫get
        def get(self):
            return HttpResponse("get请求。。。。")
        # 这个函数是固定写法,必须叫post
        def post(self):
            return HttpResponse("post请求。。。。")

    2.urls.py下使用 django的view

    python 复制代码
    from django.contrib import admin
    from django.urls import path
    from userapp import views
    urlpatterns = [
        # path('admin/', admin.site.urls),
        path('login/', views.LoginView.as_view()),
    ]
    '''
       path('login/', views.LoginView.as_view()),
       相当于:
       path('login/', View.view),
       一旦浏览器发起get请求 /login/  ------------>  View.view()
       def view(request, *args, **kwargs):
             
             self = cls(**initkwargs)
             return self.dispatch(request, *args, **kwargs)
       然后view()去调用dispatch()方法
       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
                
          # 返回loginview里的get、post方法
          return handler(request, *args, **kwargs)  
    '''

    在CBV模式下重要的是as_view()

1.2 类、面向对象基础

运算符的应用

代码:能看懂这个就能理解操作符优先级

python 复制代码
class B(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.foo()
    def foo(self):
        print("B foo....")
class Animal(B):
    foo = 100
    def foo(self):
        print("A foo...")

    foo = 100
scd = Animal("dfdk", 23)

反射:getattr()函数

python 复制代码
    class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
ads = Animal("hdsdf", 23)
atrr = input(">>>查看ads的哪个属性:")
print(getattr(ads, atrr))

反射二 getattr 方法执行通过实例对象(ads)去调用Animal类的属性和方法

getattract(self(实列对象),类中的函数)

python 复制代码
class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def foo(self):
        print("foo zhixingl")
ads = Animal("hdsdf", 23)

atrr = input(">>>查看ads的哪个属性:")
print(getattr(ads, atrr))
getattr(ads, "foo")()

1.重载(overloading method)

复制代码
是在一个类里面,方法名字相同,而参数不同。返回类型呢?可以相同也可以不同。重载是让类以统一的方式处理不同类型数据的一种手段。

函数重载主要是为了解决两个问题。
1.可变参数类型。
2.可变参数个数。

另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个名字不同的函数。

好吧,那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。

那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。

好了,鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。

2.方法重写(overiding method)

复制代码
子类不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖
python 复制代码
class LoginView(View):
    def dispatch(self, request, *args, **kwargs):
        print("dispatch....")
        # 在重写方法后,在引用父类方法需要使用super()
        super().dispatch(request, *args, **kwargs)
1.3 前后端分离模式
  • 前后端不分离模式:

    • 将数据库的数据直接嵌入模板中 实现方法是使用模板语法
    • views.py里要返回页面 使用render(),HttpResponse,redirct()
  • 前后端分离模式:

    • 使用后端的数据,queryset ,序列化(将数据库的数据传到客户端页面)、反序列化(将客户端的数据返回并保存到数据库)
1.4 API

目前市面上大多数公司开发人员使用的接口实现规范主要有:restful(基于Http协议)、RPC(基于TCP协议)性能好一些。

  • RPC (Remote Procedure Call)远程过程调用【远程服务调用】,从字面上理解就是访问/调用远程服务端提供的API接口

  • restful :面向资源开发

    符合restful 规范 urls路由:

    python 复制代码
    /books/
        get      ----- >   查看所有资源逻辑
        post     ----- >   添加逻辑
    /books/1
        get      ----- >   查看单个资源逻辑
        delete   ----- >   删除单个资源逻辑
        put      ----- >   更新单个资源逻辑
        patch    ----- >   更新资源逻辑
1.5 drf的使用
  • 在setting.py 的INSTALLED_APPS下添加" rest_framework"

  • 在urls路由中

    python 复制代码
    from django.contrib import admin
    from django.urls import path
    from userapp.views import LoginView
    from drfdemo import views
    urlpatterns = [
        # path('admin/', admin.site.urls),
        path('login/', LoginView.as_view()),
        path('student/', views.StudentView.as_view()),
    ]
    因为DRF框架的views的类视图继承的是rest_framework的APIView类
    所以 path('student/', views.StudentView.as_view()),中调用的是rest_framework的方法
    '''
    类视图继承的是rest_framework的APIView类
        def as_view(cls, **initkwargs):
        
            ########第二步调用django的View类里的as_view()函数 #######
            view = super().as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
            
            #####第三步  在View.as_view中返回view函数(dispatch()方法)
                def view(request, *args, **kwargs):
                self = cls(**initkwargs)这个self指的是APIView
                return self.dispatch(request, *args, **kwargs)
                
            #####第四步  调用APIView的dispatch方法,因为APIView中有自己的dispatch()方法
            #####第五步  看看APIView的dispatch方法的实现
            def dispatch(self, request, *args, **kwargs):
                self.args = args
                self.kwargs = kwargs
                ##### 构建新的request对象
                request = self.initialize_request(request, *args, **kwargs)
                self.request = request
                self.headers = self.default_response_headers  # deprecate?
                
                #####  执行三个组件 权限、认证(验证有点像Django的modelForms)、限流
                self.initial(request, *args, **kwargs)
                
                #####  分发逻辑(使用getattr()反射去StudentView下找到相关的函数并执行)
                handler = getattr(
                             self, request.method.lower(), self.http_method_not_allowed
                            )
                handler = self.http_method_not_allowed
    
               # 返回loginview里的get、post方法
               return handler(request, *args, **kwargs)  
    '''
  • views.py文件

    python 复制代码
    from django.shortcuts import render, HttpResponse
    # from django.views import View
    # 序列化器和检验数据的功能
    from rest_framework.views import APIView
    # Create your views here.
    class StudentView(APIView):
        def get(self, request):
            # 查看get请求传回来的数据 request.GET
            print(request.GET, type(request.GET))
            print(request.query_params)
            return HttpResponse("LoginView:get请求。。。。")
    
        def post(self, request):
    
            # 查看post请求传回来的数据 使用request.data
            print(request.data, type(request.data))
            return HttpResponse("LoginView:post请求。。。。")
    
        def delete(self, request):
            return HttpResponse("LoginView:delete请求。。。。")

    请求参数的反序列化,

    • request.data

      返回解析之后的请求体数据,类似于Django里的request.POST和request.FILES属性:

      • 包含了解析之后的文件和非文件数据
      • 包含了对POST、PUT、PATCH请求方式解析后的数据
      • 利用了REST Framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
    • request.query_params

      与DJango标准的request.GET相同,只是更换了更正确的名称而已

    • request._request

    获取django封装的Request对象

  • 序列化

    • 创建序列化类

      python 复制代码
      from rest_framework import serializers
      # 序列化类的构建
      class StudentSerializer(serializers.Serializer):
            name = serializers.CharField()
            sex = serializers.BooleanField()
            age = serializers.IntegerField()
            class_num = serializers.CharField()
    • 创建序列化对象

      python 复制代码
      class StudentView(APIView):
          def get(self, request):
              # 查看get请求传回来的数据 request.GET
              print(request.GET, type(request.GET))
              print(request.query_params)
              # 获取数据库里的所有数据,序列化对象student
              student = models.Student.objects.all()
              StudentSerializer(instance=student,)
              return HttpResponse("LoginView:get请求。。。。")
    • Serializer的创建好序列化对象构造方法(默认many=false)

      many = True 表示序列化多个数据对象

      ptyhon 复制代码
      student = models.Student.objects.all()# 可能是多个数据对象所以使用many=True
      StudentSerializer(instance=student, data=empty,many=True )# many =True 表示多个序列化数据

      说明:

      1)用序列化时,将模型类对象传入instance参数

      2)用反序列化时,将要被反序列化的数据传入data参数

      3)除了instance参数、data参数外,构造的Serializer对象时还可以通过context参数额外添加数据,如

      复制代码
      StudentSerializer(instance=student, context={"request":request} )
    • 序列化器的使用

      序列化器的使用分为两个阶段

      • 处理客户端请求时,使用序列化器可以完成对数据的反序列化
      • 处理服务端响应时,使用序列化器可以完成对数据的序列化
    • 响应器

      python 复制代码
      from rest_framework.response import Response
      return Response(serializer.data)
    • queryset\instance 转换为JSON/xml/yaml格式

  • 反序列化(添加数据)

    • 校验

      python 复制代码
          def post(self, request):
      
              # 查看post请求传回来的数据 使用request.data
              print(request.data, type(request.data))
              serializer = StudentSerializer(data=request.data)
              # 验证方法一
              try:
                  serializer.is_valid(raise_exception=True)
                  # 将数据库插入数据库
                  models.Student.objects.create(**serializer.validated_data)
              except:
                  return Response(serializer.errors)
              # 验证方法二
              if serializer.is_valid():
                  models.Student.objects.create(**serializer.validated_data)
              return Response(serializer.errors)
1.6 由Django开发API View开发
python 复制代码
from django.shortcuts import render
import json
from django.http import HttpResponse, JsonResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
# Create your views here.



courser_list = {
    'name': '课程',
    'price': 999.1
}

# FBV
@csrf_exempt
def course_list(request):
    if request.method == "GET":
        # return HttpResponse(json.dump(courser_list), content_type='application/json')
        return JsonResponse(courser_list)
    course = json.loads(request.body.decode('utf-8'))
    return JsonResponse(course, safe=False)

# CBV
@method_decorator(csrf_exempt, name='dispatch')
class CourseList(View):
    def get(self,request):
        return JsonResponse(courser_list)
    def post(self, request):
        course = json.loads(request.body.decode('utf-8'))
        return JsonResponse(course, safe=False)
1.7 由DRF 开发API view
  • 函数式编程(Function Based View)

    python 复制代码
    """ 一、DRF函数式编程  FBV (Function Based View)"""
    @api_view(["GET", "POST"])
    def course_list(request):
        if request.method == 'GET':
            course = Course.objects.all()
            sercourse = SerializerCourse(instance=course, many=True)  # 序列化
            return Response(data=sercourse.data, status=status.HTTP_200_OK)
        elif request.method == 'POST':
            s = SerializerCourse(data=request.data)   # 反序列化
            if s.is_valid():
                s.save(teacher=request.user)
                return Response(data=s.data, status=status.HTTP_201_CREATED)
            return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
  • 类试图编程(Classed Based View)

    python 复制代码
    views.py
    
    from rest_framework.decorators import api_view
    from rest_framework.response import Response
    from rest_framework import status  # 状态码
    from rest_framework.views import APIView
    from drfapp import models
    from .models import Course
    from .serializers import SerializerCourse
    
    """二、类视图 CLass Based View"""
    class CourseList(APIView):
        def get(self, request):
            # 查看get请求传回来的数据 request.GET
            print(request.GET, type(request.GET))
            print(request.query_params)
            # 获取数据库里的所有数据,序列化对象student
            s = models.Course.objects.all()
            ser = SerializerCourse(instance=s, many=True)
            return Response(data=ser.data)
        def post(self,request):
            s = SerializerCourse(data=request.data)  # 反序列化
            if s.is_valid():
                s.save()
                print(type(request.data),type(s.data))
                return Response(data=s.data, status=status.HTTP_201_CREATED)
            return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
    
    class CourseDetailList(APIView):
        @staticmethod
        def get_objects(id):
            """
            :param id: 课程id
            :return: 返回课程这个课程id的查询数据对象
            """
            try:
                return models.Course.objects.get(id=id)
            except Course.DoesNotExist:
                return
    
        def get(self, request, id):
            # 查看get请求传回来的数据 request.GET
            # 获取数据库里的所有数据,序列化对象student
            obj = self.get_objects(id=id)
            # 如果没查询的结果
            if not obj:
                return Response(data={'msg': "此课程不存在"}, status=status.HTTP_404_NOT_FOUND)
            s = SerializerCourse(instance=obj, many=False)
            print(type(request.data), type(s.data))
            return Response(data=s.data, status=status.HTTP_200_OK)
    
        def put(self, request, id):
            """
            :param request:
            :param id:
            :return:
            """
            obj = self.get_objects(id=id)
            # 如果没查询的结果
            if not obj:
                return Response(data={'msg': "此课程不存在"}, status=status.HTTP_404_NOT_FOUND)
            s = SerializerCourse(instance=obj, data=request.data)
            if s.is_valid():
                s.save()
                print(type(request.data), type(s.data))
                return Response(data=s.data, status=status.HTTP_201_CREATED)
            return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
    
    
        def delete(self, request, id):
            obj = self.get_objects(id=id)
            # 如果没查询的结果
            if not obj:
                return Response(data={'msg': "此课程不存在"}, status=status.HTTP_404_NOT_FOUND)
            obj.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
    
    urls.py 
        
    from django.urls import path, re_path, include
    from drfapp import views
    
    urlpatterns = [
        path("cbv/list/", views.CourseList.as_view()),
        path("cbv/list/<int:id>/", views.CourseDetailList.as_view())
    ]
  • 通用类视图(Generic Classed Based View)

    python 复制代码
    # 通用类导包
    from rest_framework import generics
    
    """三、通用类视图 Generic CLass Based View"""
    class GCourseList(generics.ListCreateAPIView):
        queryset = models.Course.objects.all()
        serializer_class = SerializerCourse
    
    
    
    # from rest_framework import mixins
    # from rest_framework.generics import GenericAPIView
    # class GCourseDetailList((mixins.RetrieveModelMixin,
    #                                    mixins.UpdateModelMixin,
    #                                    mixins.DestroyModelMixin,
    #                                    GenericAPIView)):
    class GCourseDetailList(generics.RetrieveUpdateDestroyAPIView):
        queryset = models.Course.objects.all()
        serializer_class = SerializerCourse
        
    urls.py
    from django.urls import path, re_path, include
    from drfapp import views
    
    urlpatterns = [
        # Class Based View
        path("cbv/list/", views.CourseList.as_view()),
        path("cbv/list/<int:id>/", views.CourseDetailList.as_view()),
        # Generic Class Based View
        path("gcbv/list/", views.GCourseList.as_view()),
        
        # 注意:这里的<int:pk>要固定写成pk
        path("gcbv/list/<int:pk>/", views.GCourseDetailList.as_view())
    ]

put和patch的区别:

put需要写全部字段并全部更新 patch 只需要写部分需要更新的字段并添加要更改的值

  • DRF的视图集viewsets

    • 方法一使用原始创建路由 url
    python 复制代码
    from django.urls import path, re_path, include
    from drfapp import views
    
    urlpatterns = [
        # Class Based View
        path("cbv/list/", views.CourseList.as_view()),
        path("cbv/list/<int:id>/", views.CourseDetailList.as_view()),
    
        # Generic Class Based View
        path("gcbv/list/", views.GCourseList.as_view()),
        path("gcbv/list/<int:pk>/", views.GCourseDetailList.as_view()),
    
        # DRF viewsets   
        ######## 方法一:
        # get的值是:viewsets.ModelViewSet继承的ListModelMixin.list
        # post值:viewsets.ModelViewSet继承的CreateModelMixin.create
    
        # get的值是:viewsets.ModelViewSet继承的RetrieveModelMixin.retrieve
        # put值:viewsets.ModelViewSet继承的UpdateModelMixin.update
        # patch值:viewsets.ModelViewSet继承的UpdateModelMixin.partial_update
        # put值:viewsets.ModelViewSet继承的DestroyModelMixin.destroy
        path("viewsets/", views.CourseViewSet.as_view(
            {"get": "list", "post": "create"}
        )),
        path("viewsets/<int:pk>/", views.CourseViewSet.as_view(
            {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}
        ))
    ]
  • DRF的视图集viewsets 方法一使用原始创建路由 url

    • 方法二 使用DRF的routers创建路由 url
    python 复制代码
    from django.urls import path, re_path, include
    from drfapp import views
    
    # DRF viewsets
    ######## 方法二使用DRF的路由:
    from rest_framework.routers import DefaultRouter
    router = DefaultRouter()
    router.register(prefix="viewsets", viewset=views.CourseViewSet)
    
    urlpatterns = [
        path("", include(router.urls))
    ]
1.8 权限与认证
  • 认证: 认证 是指一个用户登录时对其身份的校验、认证; 在setting.py进行drf权限配置 (认证是最先被执行的 然后再权限检测)

    python 复制代码
     'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.BasicAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication'
        ]
  • Token验证的生成方式

    • 使用Django的manage.py生成Token

      复制代码
      生成Token的命令
      python manage.py drf_create_token admin
    • 使用Django的信号机制生成Token

      python 复制代码
      第一步
      settings.文件下
      
      INSTALLED_APPS = [
      'rest_framework.authtoken',   # DRF 自带的Token认证
      ]
      第二步
      views.py文件下
      # 通过信号机制生成Token
      from django.db.models.signals import post_save
      from django.dispatch import receiver
      # django的user模型类
      from django.conf import settings
      from rest_framework.authtoken.models import Token
      
      # 通过信号机制生成token
      @receiver(post_save, sender=settings.AUTH_USER_MODEL)  #Django的信号机制
      def generate_token(sender, instance=None, created=False, **kwargs):
          """
          创建用户时自动生成token
          :param sender:
          :param instance:
          :param created:
          :param kwargs:
          :return:
          """
          if created:
              Token.objects.create(user=instance)
       第三步       
      drf_kan项目的总路由:drf_kan/urls.py
      from rest_framework.authtoken import views
      urlpatterns = [
          path('api-token-auth', views.obtain_auth_token), # 获取Token的接口
      ]
  • 权限:权限是指一个登录验证通过的用户能够访问哪些接口API,或者时对某个API接口能够拿到什么级别权限的数据

    python 复制代码
    'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
1.9 生成API接口文档
  • 方法一

    python 复制代码
    # 第一步
    在settings.py中
    # DRF的全局配置
    REST_FRAMEWORK = {
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',}
    #第二步
    在drf_kan项目的总路由:drf_kan/urls.py文件中
    from rest_framework.schemas import get_schema_view  # 概要  生成接口文档的包
    
    schema_view = get_schema_view(title="DRF API Document", description="xxxx")
    urlpatterns = [
        path('schema/', schema_view),
    
    ]
  • 方法二

    python 复制代码
    # 第一步
    在settings.py中
    # DRF的全局配置
    REST_FRAMEWORK = {
        # 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',}
    #第二步
    在drf_kan项目的总路由:drf_kan/urls.py文件中
    from rest_framework.documentation import include_docs_urls  # 生成接口文档的包
    
    urlpatterns = [
        path('docs/', include_docs_urls(title="DRF API Document", description="DRF快速入门"))
    
    ]

toSchema',}

#第二步

在drf_kan项目的总路由:drf_kan/urls.py文件中

from rest_framework.schemas import get_schema_view # 概要 生成接口文档的包

schema_view = get_schema_view(title="DRF API Document", description="xxxx")

urlpatterns = [

path('schema/', schema_view),

]

复制代码
- 方法二

```python
# 第一步
在settings.py中
# DRF的全局配置
REST_FRAMEWORK = {
    # 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',}
#第二步
在drf_kan项目的总路由:drf_kan/urls.py文件中
from rest_framework.documentation import include_docs_urls  # 生成接口文档的包

urlpatterns = [
    path('docs/', include_docs_urls(title="DRF API Document", description="DRF快速入门"))

]
相关推荐
代码or搬砖1 分钟前
SpringMVC的执行流程
java·spring boot·后端
杨超越luckly12 分钟前
基于 Overpass API 的城市电网基础设施与 POI 提取与可视化
python·数据可视化·openstreetmap·电力数据·overpass api
星空的资源小屋12 分钟前
跨平台下载神器ArrowDL,一网打尽所有资源
javascript·笔记·django
极光代码工作室1 小时前
基于SpringBoot的流浪狗管理系统的设计与实现
java·spring boot·后端
Rust语言中文社区1 小时前
【Rust日报】Dioxus 用起来有趣吗?
开发语言·后端·rust
小灰灰搞电子1 小时前
Rust Slint实现颜色选择器源码分享
开发语言·后端·rust
q***23571 小时前
python的sql解析库-sqlparse
数据库·python·sql
boolean的主人1 小时前
mac电脑安装nginx+php
后端
boolean的主人1 小时前
mac电脑安装运行多个php版本
后端
18你磊哥2 小时前
Django WEB 简单项目创建与结构讲解
前端·python·django·sqlite