[学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

[学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

码农世界 2024-05-22 后端 58 次浏览 0个评论

3小时搞定DRF框架 | Django REST framework前后端分离框架实践

前言(基于INSCODE AI助手)

DRF(全称Django REST framework)是一个用于构建 Web API 的强力工具集,是一个基于Django的Python Web框架,它为开发人员提供了一套快速开发 RESTful API 的工具,它能够自动化 API 可视化、文档化,实现接口的自动化测试以及自动化的API路由、序列化、视图、验证、分页、版本管理、认证等等功能。DRF简化了API的开发,并提供了一系列的工具来构建高质量的API。

1.1:课程介绍

学习目标:使用DRF开发RESTful API接口

学习内容:序列化、视图集、路由、认证、权限

课程效果:DRF的多种视图实现课程信息的增删改查

2.1: 从四个方面理解前后端分离

  • 交互形式

    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

    RESTful API是i前后端约定好的接口规范

    • 代码组织方式

      前后端不分离:django模板语法

      前后端半分离

      前后端分离

    • 开发模式

      前后端不分离项目开发流程:

      [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

      前后端分离项目开发流程:

      [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

    • 数据接口规范流程

      [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

      2.2 深入理解什么是RESTful API

      可以学习别人的接口规范学习。

      例如:

      github-API

      [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

      [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

      深入理解什么是RESTful API

      2.3 Pycharm搭建项目开发环境

      • Settings.py
        # 因为RESTframework是有前端文件的,后面使用时会全部放到这个目录
        STATIC_ROOT = os.pardir.join(BASE_DIR, "static")
        STATICFILES_DIRS = [
            os.path.join(BASE_DIR, "staticfiles")
        ]
        
        • manage.py
          makemigrations
          migrate
          createsuperuser
          

          [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

          2.4 framework介绍和安装

          django rest framework官网:https://www.django-rest-framework.org/

          按照文档执行下面步骤:

          • 1.安装相应包
            pip install djangorestframework
            pip install markdown       # Markdown support for the browsable API.
            pip install django-filter  # Filtering support
            
            • 在settings.py中修改配置
              # Add 'rest_framework' to your INSTALLED_APPS setting.
              INSTALLED_APPS = [
                  ...
                  "rest_framework", # 用于开发RESTful API
                  'rest_framework.authtoken', # DRF自带的Token认证
              ]
              

              对于rest framework所有相关配置都放在settings的一个字典里面

              # DRF的全局配置
              REST_FRAMEWORK = {
                  'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',  # 自带分页类
                  'PAGE_SIZE': 50,  # 每页数据量
                  'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',  # 时间显示格式
                  'DEFAULT_RENDER_CLASSES': [
                      'rest_framework.renders.JSONRenderer',
                      'rest_framework.renders.BrowsableAPIRenderer',
                  ],  # 返回response对象所用的类
                  'DEFAULT_PARSER_CLASSES': [
                      'rest_framework.parsers.JSONParser',
                      'rest_framework.parsers.FormParser',
                      'rest_framework.parsers.MultiPartParser',
                  ],  # 解析器,如何解析request请求中的request.data
                  'DEFAULT_PERMISSION_CLASSES': [
                      'rest_framework.permissions.IsAuthenticated',
                  ],  # 权限相关配置
                  'DEFAULT_AUTHENTICATION_CLASSES': [
                      'rest_framework.authentication.BasicAuthentication',
                      'rest_framework.authentication.SessionAuthentication',
                      'rest_framework.authentication.TokenAuthentication',
                  ],  # 认证相关配置
                  "URL_FIELD_NAME": 'link',
              }
              
              • 在urls.py中修改配置
                urlpatterns = [
                    ...
                    path('api-auth/', include('rest_framework.urls')) # DRF的登录退出
                ]
                
                • DRF的20个模块

                  序列化、视图、路由、认证、权限、限流、过滤、解析器、渲染器、分页、版本、测试、概要、异常处理、配置、验证、状态码、内容协商、缓存、元数据

                  3.1 开发课程信息模型类

                  models.py

                  from django.db import models
                  # Create your models here.
                  from django.db import models
                  from django.conf import settings
                  class Course(models.Model):
                      name = models.CharField(max_length=255, unique=True, help_text='课程名称', verbose_name='名称')
                      introduction = models.TextField(help_text='课程介绍', verbose_name='介绍')
                      teacher = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, help_text='课程讲师', verbose_name='讲师')
                      price = models.DecimalField(max_digits=6, decimal_places=2, help_text='课程价格')
                      created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
                      update_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
                      class Meta:
                          verbose_name = "课程信息"
                          verbose_name_plural = verbose_name
                          ordering = ('price',)
                      def __str__(self):
                          return self.name
                  

                  将字段注册到后台,方便从admin后台添加数据

                  admin.py

                  from django.contrib import admin
                  from .models import Course
                  # Register your models here.
                  @admin.register(Course)
                  class CourseAdmin(admin.ModelAdmin):
                      list_display = ('name', 'introduction', 'teacher', 'price')
                      search_fields = list_display
                      list_filter = list_display
                  

                  3.2 什么是序列化

                  序列化也叫序列化器,是指把查询集QuerySet或者模型类实例instance这种django的数据类型转化为json或者xml

                  把queryset或者instance转化为方便前端可以轻松渲染的json/xml/yaml

                  所以序列化和反序列化是为了前后端数据交互

                  深度剖析 Django 的 serializer

                  • 启动项目,进入admin后台,插入数据

                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                  • 在python console中测试django的序列化器

                    from course.models import Course
                    from django.core import serializers
                    serializers.serialize('json', Course.objects.all())
                    # '[{"model": "course.course", "pk": 1, "fields": {"name": "Django REST framework快速入门", "introduction": "快速入门Django REST framework,学会开发一套自己的Restful API服务,并且自动生成API文档", "teacher": 1, "price": "9.99", "created_at": "2023-07-28T10:11:46.882", "update_at": "2023-07-28T10:11:46.882"}}]'
                    # 如果只需要序列化一部分字段
                    serializers.serialize('json', Course.objects.all(), fields=("name"))
                    # '[{"model": "course.course", "pk": 1, "fields": {"name": "Django REST framework快速入门"}}]'
                    

                    但django的序列化器还有很多需要完善的地方

                    1.验证处理:在反序列化的过程中,当前端传递过来的数据放在request.data里时,要转化为模型类实例,然后保存。这时需要对前端提交的数据进行验证。

                    2.验证器的参数

                    3.同时序列化多个对象

                    4.序列化的过程中添加上下文

                    5.没有对无效的数据异常处理

                    6.关系型字段的外键字段只返回了id,需要我们自己处理关系型字段

                    drf的序列化器可以帮我们很好的解决这些问题。

                    3.3 如何继承ModelSerializer序列化模型类

                    Python学习————序列化器(复习

                    在应用下建一个serializes.py

                    模型类的序列化的写法和django开发时form的写法非常类似

                    先回顾给模型类建form表单类

                    from django import forms
                    from rest_framework import serializers  # 导入序列化器
                    from .models import Course
                    class CourseForm(forms.ModelForm):
                        class Meta:
                            model = Course
                            fields = ('name', 'introduction', 'teacher', 'price')
                    

                    模型类序列化的写法几乎一样,只是继承自serializers.ModelSerializer

                    teacher是外键,所以想得到讲师对应的名字,需要把用户的名称序列化出来。

                    teacher关联到的用户表,并不是新建课程时新建一个用户,所以该字段可以设为只读ReadOnlyField

                    class CourseSerializer(serializers.ModelSerializer):
                        teacher = serializers.ReadOnlyField(source='teacher.username') # 外键字段、只读
                        
                        class Meta:
                            model = Course  # 写法和上面的CourseForm类似
                            # exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")
                            # fields = ('name', 'introduction', 'teacher', 'price')
                            fields = "__all__"
                    

                    同样方法序列化用户模型类

                    ModelSerializer是更高一级的封装,它继承自Serializer,要实现比较灵活的自定义,可以继承自Serializer

                    我们这里只序列化模型类,比较简单,所以可以直接用

                    from django.contrib.auth.models import User
                    class UserSerializer(serializers.ModelSerializer):
                        class Meta:
                            model = User
                            fields = "__all__"
                    

                    对外键字段的序列化,可以指定遍历的深度

                    如果表结构有子表关联到父表,父表又关联到另外的父表,就可以设置深度

                    class CourseSerializer(serializers.ModelSerializer):
                        teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键字段、只读
                        class Meta:
                            model = Course  # 写法和上面的CourseForm类似
                            # exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")
                            # fields = ('name', 'introduction', 'teacher', 'price')
                            fields = "__all__"
                            depth = 2  # 深度
                    

                    3.4 带URL的HyperlinkedModelSerializer

                    假设请求课程信息时,希望每条课程信息的记录,都能跳转到详情页

                    DRF相关的配置,都写在settings.py中的REST_FRAMEWORK的字典中

                    继承自HyperlinkedModelSerializer

                    fields里加上url

                    url是默认值,如果要改成其他名称,如“link”,可在settings.py中设置URL_FIELD_NAME使全局生效

                    settings.py

                    # DRF的全局配置
                    REST_FRAMEWORK = {
                        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',  # 自带分页类
                        'PAGE_SIZE': 50,  # 每页数据量
                        'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',  # 时间显示格式
                        'DEFAULT_RENDER_CLASSES': [
                            'restframework.renders.JSONRenderer',
                            'restframework.renders.BrowsableAPIRenderer',
                        ],  # 返回response对象所用的类
                        'DEFAULT_PARSER_CLASSES': [
                            'rest_framework.parsers.JSONparser',
                            'rest_framework.parsers.Formparser',
                            'rest_framework.parsers.MultiPartparser',
                        ],  # 解析器,如何解析request请求中的request.data
                        'DEFAULT_PERMISSION_CLASSES': [
                            'rest_framework.permissions.IsAuthenticated',
                        ],  # 权限相关配置
                        'DEFAULT_AUTHENTICATION_CLASSES': [
                            'rest_framework.authentication.BasicAuthentication',
                            'rest_framework.authentication.SessionAuthentication',
                            'rest_framework.authentication.TokenAuthentication',
                        ],  # 认证相关配置
                        "URL_FIELD_NAME": 'link',
                    }
                    

                    serializers.py

                    class CourseSerializer(serializers.HyperlinkedModelSerializer):
                        teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键字段、只读
                        class Meta:
                            model = Course  # 写法和上面的CourseForm类似
                            # url是默认值,可在settings.py中设置URL_FIELD_NAME使全局生效
                            # fields = ('id', 'url', 'name', 'introduction', 'teacher', 'price', 'created_at', 'update_at')
                            fields = ('id', 'link', 'name', 'introduction', 'teacher', 'price', 'created_at', 'update_at')
                    

                    4.1 Django的views开发RESTful API接口

                    通过DRF使用四种不同的方式来Restful API接口

                    • 函数式编程
                    • 类视图
                    • 通用类视图
                    • DRF的视图集

                      在views.py文件中

                      4.1.1 Django原生的view-函数式编程编写API接口

                      思路就是判断这个是什么方法,然后进行处理

                      @csrf_exempt
                      def course_list(request):
                          course_dict = {
                              'name': '课程名称',
                              'introduction': '课程介绍',
                              'price': 0.11
                          }
                          if request.method == "GET":
                              # return HttpResponse(json.dumps(course_dict), content_type='application/json')
                              return JsonResponse(course_dict) # 这两种写法是等价的
                          if request.method == "POST":
                              course = json.loads(request.body.decode('utf-8'))
                              return JsonResponse(course, safe=False) # 如果解析的数据不是字典类型,是字符串的话,需要使用safe=false
                      

                      需要注意:post请求,需要使用装饰器来解除csrf限制

                      4.1.2 Django原生的view-类视图编程编写API接口

                      CBV的编写思路是对不同的请求方法用对应的函数处理

                      import json
                      from django.http import JsonResponse, HttpResponse
                      from django.views import View
                      from django.views.decorators.csrf import csrf_exempt
                      from django.utils.decorators import method_decorator
                      # Django CBV 编写API接口
                      @method_decorator(csrf_exempt, name='dispatch')
                      class CourseList(View):
                          def get(self, request):
                              return JsonResponse(course_dict)
                          @csrf_exempt
                          def post(self, request):
                              course = json.loads(request.body.decode('utf-8'))
                              return JsonResponse(course, safe=False)  # 如果解析的数据不是字典类型,是字符串的话,需要使用safe=false
                      

                      可以导入方法装饰器,装饰的方法是是dispatch,因为根据django的请求响应原理,当request请求来的时候,它首先到达dispatch方法,通过dispatch方法处理后,再找到post方法

                      上面的两种方式,是直接使用原生的Django写接口,有很多东西都需要自己从零开始实现。

                      比如分页、排序、认证、权限、限流等等

                      于是就有了DRF的视图,集成了这些接口开发常用的功能

                      4.2 DRF的装饰器api_view - 函数式编程

                      4.2.1 实现“获取所有课程信息或新增一个课程”的接口

                      • 新建drf的fbv视图
                        from rest_framework.decorators import api_view
                        from rest_framework.response import Response # django使用的是JsonResponse或HttpResponse,而drf直接封装好了,就是Response
                        from rest_framework import status
                        from .models import Course
                        from .serializers import CourseSerializer
                        """一、函数式编程 Function Based View"""
                        @api_view(["GET", "POST"])
                        def course_list(request):
                            """
                            获取所有课程信息或新增一个课程
                            :param request:
                            :return:
                            """
                            if request.method == "GET":
                                s = CourseSerializer(instance=Course.objects.all(), many=True) # 序列化多个对象,所以需要many=True
                                # 序列化后的数据可以通过s.data获得
                                return Response(data=s.data, status=status.HTTP_200_OK)
                            elif request.method == "POST":
                                s = CourseSerializer(data=request.data, partial=True) # 反序列化, partial=True表示部分更新
                                if s.is_valid():
                                    s.save(teacher=request.user) # 讲师是只读属性
                                    return Response(data=s.data, status=status.HTTP_201_CREATED)
                                return Response(s.erros, status=status.HTTP_400_BAD_REQUEST)
                        

                        函数式编程会用到装饰器

                        partial=True表示部分更新

                        • 新建路由

                          为了方便管理course这个app下的路由,在course这个应用下创建一个urls.py文件,然后通过include包含到项目的urls中

                          django urls include用法

                          course/urls.py

                          from django.urls import path
                          from course import views
                          urlpatterns = [
                              # Function Based View
                              path("fbv/list/", views.course_list, name="fbv-list")
                          ]
                          

                          drf_tutorial/urls.py

                          urlpatterns = [
                              path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
                              path("admin/", admin.site.urls),
                              path('course/', include('course.urls'))
                          ]
                          

                          [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                          先不用HyperlinkedModelSerializer的api了,因为HyperlinkedModelSerializer是高度集成的序列化类,后面使用drf的视图集来编程可以用。所以序列化类改用:

                          class CourseSerializer(serializers.ModelSerializer):
                              teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键字段、只读
                              class Meta:
                                  model = Course  # 写法和上面的CourseForm类似
                                  # exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")
                                  # fields = ('name', 'introduction', 'teacher', 'price')
                                  fields = "__all__"
                                  depth = 2  # 深度
                          
                          • 返回结果

                            [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                          • 测试post请求

                            [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                            4.2.2 实现“获取一个课程信息或更新删除某个课程信息”的接口

                            • 实现视图
                              @api_view(["GET", "PUT", "DELETE"])
                              def course_detail(request, pk): # 通过url传递pk
                                  """
                                  获取、更新、删除一个课程
                                  :param request:
                                  :param pk:
                                  :return:
                                  """
                                  try:
                                      course = Course.objects.get(pk=pk)
                                  except Course.DoesNotExist:
                                      return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
                                  else:
                                      if request.method == "GET":
                                          s = CourseSerializer(instance=course) # 序列化一个对象不需要many=True
                                          return Response(data=s.data, status=status.HTTP_200_OK)
                                      elif request.method == "PUT": # PUT方法表示更新,部分写法和POST方法类似
                                          s = CourseSerializer(instance=course, data=request.data) #instance是指要序列化哪个实例,data表示数据哪里来的
                                          # 表示把data的数据,反序列化之后,保存或者更新到cuorse对象里
                                          if s.is_valid():
                                              s.save() # 不需要teacher字段
                                              return Response(s.data, status=status.HTTP_200_OK)
                                      elif request.method == "DELETE":
                                          course.delete()
                                          return Response(status=status.HTTP_204_NO_CONTENT)
                              
                              • 实现路由
                                urlpatterns = [
                                    # Function Based View
                                    path("fbv/list/", views.course_list, name="fbv-list")
                                    path("fbv/detail/", views.course_detail, name="fbv-detail")
                                ]
                                

                                4.3 如何使用Postman测试API接口(我这里是apipost)

                                我这里以apipost为例

                                认证方式:

                                • basic auth认证:账户名、密码认证

                                • api key认证:token认证

                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                • OAuth 2.0等

                                  要在请求头加一些key,value,可以点header

                                  query是url带上的参数

                                  后端代码里解析的request.data,一般是放在raw里面

                                  • Post请求

                                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                  • Get请求

                                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                    4.4 DRF中的视图APIView - 类视图编程

                                    4.4.1 实现“获取所有课程信息或新增一个课程”的接口

                                    • 导入APIView
                                      from rest_framework.views import APIView
                                      
                                      • 实现类视图
                                        """二、类视图 Class Based View"""
                                        class CourseList(APIView):
                                            def get(self, request):
                                                """
                                                :param request:
                                                :return:
                                                """
                                                queryset = Course.objects.all()
                                                s = CourseSerializer(instance=queryset, many=True)
                                                return Response(s.data, status=status.HTTP_200_OK)
                                            def post(self, request):
                                                """
                                                :param request:
                                                :return:
                                                """
                                                s = CourseSerializer(data=request.data)
                                                if s.is_valid():
                                                    s.save(teacher=self.request.user)
                                                    print(type(request.data), type(s.data))
                                                    # 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)
                                        
                                        • 新建路由
                                          urlpatterns = [
                                              # Function Based View
                                              path("fbv/list/", views.course_list, name="fbv-list"),
                                              path("fbv/detail//", views.course_detail, name="fbv-detail"),
                                              # Class Based View
                                              path("cbv/list/", views.CourseList.as_view(), name='cbv-list')
                                          ]
                                          
                                          • 测试请求

                                            [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                            [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                            4.4.2 实现“详情页”的接口

                                            静态方法:无论是通过类对象直接调用还是实例对象进行调用都是可以的,需要注意的是在静态方法中无法使用实例属性和方法

                                            python静态方法、实例方法、类方法使用

                                            • 实现接口
                                              class CourseDetail(APIView):
                                                  @staticmethod  # 静态方法
                                                  def get_object(pk):
                                                      """
                                                      :param pk:
                                                      :return:
                                                      """
                                                      try:
                                                          return Course.objects.get(pk=pk)
                                                      except Course.DoesNotExist:
                                                          return
                                                  def get(self, request, pk):
                                                      """
                                                      :param request:
                                                      :param pk:
                                                      :return:
                                                      """
                                                      obj = self.get_object(pk=pk)
                                                      if not obj:
                                                          return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
                                                      s = CourseSerializer(instance=obj)
                                                      return Response(s.data, status=status.HTTP_200_OK)
                                                  def put(self, request, pk):
                                                      obj = self.get_object(pk=pk)
                                                      if not obj:
                                                          return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
                                                      s = CourseSerializer(instance=obj, data=request.data)
                                                      if s.is_valid():
                                                          s.save()
                                                          return Response(data=s.data, status=status.HTTP_200_OK)
                                                      return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
                                                  def delete(self, request, pk):
                                                      """
                                                      :param request:
                                                      :param pk:
                                                      :return:
                                                      """
                                                      obj = self.get_object(pk=pk)
                                                      if not obj:
                                                          return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
                                                      obj.delete()
                                                      return Response(status=status.HTTP_204_NO_CONTENT)
                                              
                                              • 实现路由
                                                urlpatterns = [
                                                    # Function Based View
                                                    path("fbv/list/", views.course_list, name="fbv-list"),
                                                    path("fbv/detail//", views.course_detail, name="fbv-detail"),
                                                    # Class Based View
                                                    path("cbv/list/", views.CourseList.as_view(), name='cbv-list'),
                                                    path("cbv/detail//", views.CourseDetail.as_view(), name='cbv-detail'),
                                                ]
                                                
                                                • 测试请求

                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                  类视图编程方法和函数式编程的编写方法,代码几乎一样。下一小节讲解更加简洁的编写方法。

                                                  4.5 DRF中的通用类视图GenericAPIView

                                                  导入generics

                                                  from rest_framework import generics
                                                  

                                                  4.5.1 实现查看和请求新增的接口

                                                  通用类视图,实际上是把一些常见的增删改查操作对应的类通过mixin把他混合在一起。

                                                  这里属性的名称是固定的

                                                  这里需要重载perform_create方法

                                                  4.5.2 实现课程详情的接口

                                                  • 实现通用类视图

                                                    下面的写法等价于class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):

                                                    不过对于下面的方法,请求的方法不再是GET、PUT、PATCH、DELETE,而是retrieve,update,destory等,所以还是建议用class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):

                                                    from rest_framework import mixins
                                                    from rest_framework.generics import GenericAPIView
                                                    class GCourseDetail(generics.mixins.RetrieveModelMixin,
                                                                                       mixins.UpdateModelMixin,
                                                                                       mixins.DestroyModelMixin,
                                                                                       GenericAPIView):
                                                        queryset = Course.objects.all()
                                                        serializer_class = CourseSerializer
                                                    
                                                    • 新增路由
                                                      urlpatterns = [
                                                          # Function Based View
                                                          path("fbv/list/", views.course_list, name="fbv-list"),
                                                          path("fbv/detail//", views.course_detail, name="fbv-detail"),
                                                          # Class Based View
                                                          path("cbv/list/", views.CourseList.as_view(), name='cbv-list'),
                                                          path("cbv/detail//", views.CourseDetail.as_view(), name='cbv-detail'),
                                                          # Generic Class Based View
                                                          path("gcbv/list/", views.GCourseList.as_view(), name='gcbv-list'),
                                                          path("gcbv/detail//", views.GCourseDetail.as_view(), name='gcbv-detail'),
                                                      ]
                                                      
                                                      • 测试请求

                                                        [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                        通用类视图里面还做好了其他事情:总个数(count)、下一页(next)、上一页(previous)、数据(results)

                                                        [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                        [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                        4.6 DRF的viewsets开发课程信息的增删改查接口 - 视图集

                                                        • 导入viewsets
                                                          from rest_framework import viewsets
                                                          
                                                          • 创建视图集
                                                            """四、DRF的视图集"""
                                                            class CourseViewSet(viewsets.ModelViewSet):
                                                                queryset = Course.objects.all()
                                                                serializer_class = CourseSerializer
                                                                
                                                                def perform_create(self, serializer):
                                                                    serializer.save(teacher=self.request.user)
                                                            

                                                            不做权限认证只需要四行代码

                                                            4.7 Django的URLs与DRF的Routers

                                                            • 新增路由

                                                              写法和前面不一样

                                                              两种视图集的路由写法

                                                                • 1 传统写法
                                                                      # DRF viewsets
                                                                      path("viewsets/", views.CourseViewSet.as_view(
                                                                          {"get": "list", "post": "create"}
                                                                      ), name="viewsets-list"),
                                                                      path("viewsets//", views.CourseViewSet.as_view(
                                                                          {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destory"}
                                                                      ), name="viewsets-detail")
                                                                  
                                                                    • 2.DRF的路由routers
                                                                    • 导入
                                                                      from rest_framework.routers import DefaultRouter
                                                                      router = DefaultRouter() # 把类实例化
                                                                      router.register(prefix="viewsets", viewset=views.CourseViewSet) # 把视图集注册到这个路由实例里面
                                                                      urlpatterns = [
                                                                          path("", include(router.urls))
                                                                      ]
                                                                      
                                                                      • 测试接口

                                                                        [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                        5.1 DRF认证方式介绍

                                                                        DRF常用的三种认证方式:

                                                                        1.BasicAuthentication:用户名密码认证

                                                                        2.SessionAuthentication:Session认证

                                                                        3.TokenAuthentication:Token认证

                                                                        [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                        也可以实现自定义的认证方案,或者使用第三方的包,比如json webtoken(关于jwt的认证,会在接下来的drf进阶实战课程讲解)

                                                                        认证和权限的区别:

                                                                        认证是对用户登录的身份进行校验

                                                                        权限指的是一个登录验证通过的用户,他能够访问哪些接口;或者对于某一个接口,他能够拿到什么级别的数据

                                                                        根据Django restframework对http request的响应流程来看,身份认证是发生在权限检查和限流检查之前的

                                                                        认证和权限,核心依赖两个数据:request.user, request.auth

                                                                        认证机制实际上依赖的是Django的auth框架

                                                                        'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ],

                                                                        中的多个认证类,DRF会按顺序从上往下对每个类进行认证。并使用第一个成功通过的认证类来返回值,来设置request.user和request.auth

                                                                        5.1.1 BasicAuthentication

                                                                        设置basicauthentication,则headers会多一个authorization,它是用户名密码经过base64库计算出来的密文,这是postman自动完成的。base64库不具有机密性,是可以解密的。所以basicauthentication一般用于测试工作,不用于生产环境

                                                                        • 测试,通过basicauthentication认证后,request.user和request.auth返回什么
                                                                          print(self.request.user, self.request.auth)
                                                                          print(type(self.request.user), type(self.request.auth))
                                                                          # admin None
                                                                          #  
                                                                          
                                                                          • 查看响应头有什么信息

                                                                            密码正确

                                                                            [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                            密码错误

                                                                            认证失败的话会在响应头里面多一个WWW_Authenticate字段

                                                                            [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                            5.1.2 SessionAuthentication

                                                                            使用的是Django默认的会话后端,通常在前端js里使用http,ajax请求时可以使用session认证,使用这个时,需要给后端提供csrf令牌的。

                                                                            5.1.3 TokenAuthentication

                                                                            是一种简单的,基于令牌的http认证方式

                                                                            • 在settings.py的INSTALLED_APPS加上'rest_framework.authtoken'

                                                                              会生成一张数据表

                                                                              INSTALLED_APPS = [
                                                                                  "django.contrib.admin",
                                                                                  "django.contrib.auth",
                                                                                  "django.contrib.contenttypes",
                                                                                  "django.contrib.sessions",
                                                                                  "django.contrib.messages",
                                                                                  "django.contrib.staticfiles",
                                                                                  "rest_framework",  # 用于开发RESTful API
                                                                                  'rest_framework.authtoken',  # DRF自带的Token认证
                                                                                  'course.apps.CourseConfig',
                                                                              ]
                                                                              
                                                                              • 生成token的方式
                                                                                5.1.3.1 使用Django manag.py生成Token

                                                                                只能供管理员测试

                                                                                手动生成token

                                                                                python manage.py drf_create_token admin #给admin建一个token
                                                                                

                                                                                [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                5.1.3.2 使用Django的信号机制生成Token

                                                                                目的:

                                                                                自动生成token

                                                                                用户可以通过接口请求到token

                                                                                view.py中

                                                                                from django.db.models.signals import post_save # 保存之后,即用户已经建好之后的信号
                                                                                from django.conf import settings
                                                                                from django.dispatch import receiver # 接收信号
                                                                                from rest_framework.authtoken.models import Token
                                                                                @receiver(post_save, sender=settings.AUTH_USER_MODEL)
                                                                                def generate_token():
                                                                                

                                                                                也可以直接导入django的user模型类作为认证模型类:from django.contrib.auth.models import User

                                                                                原理:当User模型类新建一个实例并把并保存的时候,即新建一个用户的时候,因为保存要调用save方法

                                                                                保存之后,post_save信号会传递给receiver,receiver接受之后,就会执行函数generate_token

                                                                                执行函数时,instance是指新建的用户实例,created=True,于是在authtoken_token表中生成一条记录

                                                                                给用户生成的token,用户如何获取到呢?

                                                                                rest_framework已经帮我们写好了,我们直接调用即可

                                                                                在总的路由urls.py中

                                                                                from django.contrib import admin
                                                                                from django.urls import path, include
                                                                                from rest_framework.authtoken import views
                                                                                urlpatterns = [
                                                                                    path("api-token-auth/", views.obtain_auth_token), # 获取token的接口
                                                                                    path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
                                                                                    path("admin/", admin.site.urls),
                                                                                    path('course/', include('course.urls'))
                                                                                ]
                                                                                
                                                                                • 测试-新建用户

                                                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                  user01 - mima123456

                                                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                  可以看到token表中有新增记录

                                                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                • 测试,通过postman,通过接口获取token

                                                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                • 认证成功

                                                                                  [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                  请求头

                                                                                  print(self.request.user, self.request.auth)
                                                                                  print(type(self.request.user), type(self.request.auth))
                                                                                  # user01 e1e4eb90e389feb76c8bb71ad73e3b3c63e8090c
                                                                                  #  
                                                                                  

                                                                                  认证成功的话,request.user依旧是django的user类实例

                                                                                  request.auth是Token类实例

                                                                                  响应头里面没有和认证有关的信息

                                                                                  • 认证失败

                                                                                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                  • 要对某一个接口,去使用不同的认证的方式

                                                                                    不论使用什么视图编程方式,都有对应的设置方法。下面按照四种不同的视图编程方式,分别讲解。

                                                                                      • 1.对函数式编程

                                                                                        导入对于认证的装饰类:

                                                                                        from rest_framework.decorators import api_view, authentication_classes
                                                                                        from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication
                                                                                        

                                                                                        装饰器是有顺序的

                                                                                        对象上只添加密码认证的类装饰器

                                                                                        @api_view(["GET", "POST"])
                                                                                        @authentication_classes((BasicAuthentication, )) # 对象级别的认证设置,优先于全局设置
                                                                                        def course_list(request):
                                                                                            """
                                                                                            获取所有课程信息或新增一个课程
                                                                                            :param request:
                                                                                            :return:
                                                                                            """
                                                                                            if request.method == "GET":
                                                                                                s = CourseSerializer(instance=Course.objects.all(), many=True)  # 序列化多个对象,所以需要many=True
                                                                                                # 序列化后的数据可以通过s.data获得
                                                                                                return Response(data=s.data, status=status.HTTP_200_OK)
                                                                                            elif request.method == "POST":
                                                                                                s = CourseSerializer(data=request.data, partial=True)  # 反序列化, partial=True表示部分更新
                                                                                                if s.is_valid():
                                                                                                    s.save(teacher=request.user)  # 讲师是只读属性
                                                                                                    return Response(data=s.data, status=status.HTTP_201_CREATED)
                                                                                                return Response(s.erros, status=status.HTTP_400_BAD_REQUEST)
                                                                                        
                                                                                        • 测试

                                                                                          [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                          注意写法,必须是Token xxx

                                                                                            • 2.对类视图编程

                                                                                              直接加入类属性authentication_classes

                                                                                              class CourseList(APIView):
                                                                                                  authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
                                                                                              

                                                                                              通用类视图、视图集也是一样的,也都有类属性

                                                                                              5.3 DRF的权限控制

                                                                                              常用的权限类有哪些?应该如何设置权限策略?如何自定义对象级别权限?

                                                                                              DRF的权限都是在permissions模块里面,权限检查的过程和前面讲解的身份认证一样,也是会使用request.user和request.auth属性中的身份认证信息来决定请求是否传入。、

                                                                                              5.3.1 在settings.py中可以设置全局的权限类

                                                                                              [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                              • 常用权限类有:

                                                                                                IsAuthenticatedOrReadOnly: 登录的用户可以增删改查,不登陆的用户可以查询

                                                                                                IsAuthenticated:只有登录的用户可以进行所有操作,不登陆的用户不能进行所有操作,get也不行

                                                                                                IsAdminUser:admin用户有权限访问接口,是不是admin是看auth_user表的is_staff字段,true表示是admin级别用户

                                                                                                AllowAny:允许所有请求

                                                                                                5.3.2 如何在接口上/对象级别设置权限

                                                                                                • 导入装饰器
                                                                                                  from rest_framework.decorators import api_view, authentication_classes, permission_classes
                                                                                                  
                                                                                                  • 导入权限类
                                                                                                    在这里插入代码片
                                                                                                    
                                                                                                    5.3.2.1 给函数视图设置权限
                                                                                                    • 给函数视图加上装饰器
                                                                                                      @api_view(["GET", "POST"])
                                                                                                      @authentication_classes((BasicAuthentication, ))  # 对象级别的认证设置,优先于全局设置
                                                                                                      @permission_classes((IsAuthenticated, )) # 自定义的权限类
                                                                                                      def course_list(request):
                                                                                                      
                                                                                                      5.3.2.2 给类视图/通用类视图/视图集设置权限
                                                                                                      • 直接加入类属性authentication_classes
                                                                                                        permission_classes = (IsAuthenticated, )
                                                                                                        

                                                                                                        5.3.3 如何自定义对象级别权限?

                                                                                                        实现只能修改自己的信息,别人的信息只可以查看,不能修改。

                                                                                                        • 在应用下面建立permission.py,并创建自定义的权限类

                                                                                                          permission.py

                                                                                                          class IsOwnerReadOnly(permissions.BasePermission):
                                                                                                              """
                                                                                                              自定义权限:只有对象的所有者可以增删改查
                                                                                                              """
                                                                                                              def has_object_permission(self, request, view, obj):  # 重写BasePermission的方法
                                                                                                                  """
                                                                                                                  所有的request请求都有读权限,因此一律允许GET/HEAD/OPTIONS方法
                                                                                                                  如果用户是自己,可以修改
                                                                                                                  :param request:
                                                                                                                  :param view:
                                                                                                                  :param obj:
                                                                                                                  :return: bool
                                                                                                                  """
                                                                                                                  if request.method in permissions.SAFE_METHODS:
                                                                                                                      return True
                                                                                                                  # 对象的所有者才有写权限
                                                                                                                  return obj.teacher == request.user
                                                                                                          

                                                                                                          重写has_object_permission方法

                                                                                                          安全的方法("GET", "HEAD", "OPTIONS")可以用permissions.SAFE_METHODS代替

                                                                                                          [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                          • 将创好的自定义权限类导入视图
                                                                                                            from .permission import IsOwnerReadOnly
                                                                                                            class GCourseList(generics.ListCreateAPIView):
                                                                                                                queryset = Course.objects.all()
                                                                                                                serializer_class = CourseSerializer
                                                                                                                permission_classes = (IsAuthenticated, )
                                                                                                                def perform_create(self, serializer):
                                                                                                                    serializer.save(teacher=self.request.user)
                                                                                                            class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
                                                                                                                queryset = Course.objects.all()
                                                                                                                serializer_class = CourseSerializer
                                                                                                                permission_classes = (IsAuthenticated, IsOwnerReadOnly)
                                                                                                            
                                                                                                            • 测试接口

                                                                                                              [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                              [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                              6.1 如何生成API接口文档

                                                                                                              6.1.1 如何生成API接口文档

                                                                                                              通过请求url可以查看单个接口的格式等信息。但是有没有方法展示所有接口信息,即API在线文档

                                                                                                              这样能方便前端查看,一目了然

                                                                                                              下面操作必须要先pip install coreapi

                                                                                                              • 1.在settings.py的REST_FRAMEWORK中加入
                                                                                                                REST_FRAMEWORK = {
                                                                                                                    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
                                                                                                                    ...
                                                                                                                    }
                                                                                                                
                                                                                                                • 2.在总的urls.py中添加路由

                                                                                                                  先导入get_schema_view

                                                                                                                  再创建get_schema_view实例

                                                                                                                  再创建路由

                                                                                                                  from rest_framework.schemas import get_schema_view
                                                                                                                  schema_view = get_schema_view(title="DRF API文档", description="xxx")
                                                                                                                  urlpatterns = [
                                                                                                                      path("api-token-auth/", views.obtain_auth_token), # 获取token的接口
                                                                                                                      path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
                                                                                                                      path("admin/", admin.site.urls),
                                                                                                                      path('course/', include('course.urls')),
                                                                                                                      path('schema/', schema_view),
                                                                                                                  ]
                                                                                                                  
                                                                                                                  • 测试

                                                                                                                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                                    建议在Chrome应用商店下载jsonView插件

                                                                                                                    点击GET-corejson

                                                                                                                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                                    [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                                    但是文档还是不够美观,下一节介绍使用coreapi的概要功能

                                                                                                                    6.2 DRF的概要使用方法介绍

                                                                                                                    coreapi应该如何配置,以及文档的使用方法。

                                                                                                                    • 修改REST_FRAMEWORK的’DEFAULT_SCHEMA_CLASS’属性

                                                                                                                      [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                                    • 在urls.py中
                                                                                                                      • 1.导入模块,新增路由
                                                                                                                        from rest_framework.documentation import include_docs_urls
                                                                                                                        urlpatterns = [
                                                                                                                            path("api-token-auth/", views.obtain_auth_token),  # 获取token的接口
                                                                                                                            path('api-auth/', include('rest_framework.urls')),  # DRF的登录退出
                                                                                                                            path("admin/", admin.site.urls),
                                                                                                                            path('docs/', include_docs_urls(title='DRF API文档', description='Django REST framework快速入门')),
                                                                                                                            path('course/', include('course.urls')),
                                                                                                                        ]
                                                                                                                        
                                                                                                                        • 测试

                                                                                                                          [学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践

                                                                                                                          在这个API文档中,认证配置好之后,刷新之后需要重新配置

                                                                                                                          7.1 课程总结

                                                                                                                          • 应该使用哪种视图开发?

                                                                                                                            使用函数式视图编写灵活,但是这是面向过程的方式,重复率高

                                                                                                                            使用类视图,可以用到python中类的特性,封装、继承、多态,减少代码重复率

                                                                                                                            通用类视图,灵活度就比较低了

                                                                                                                            视图集高度定制化,灵活度最低

                                                                                                                            一般以类视图编程为主。

                                                                                                                          • DRF的运行机制?APIView源码?测试?缓存?限流。。。都没有讲到

转载请注明来自码农世界,本文标题:《[学习笔记]3小时搞定DRF框架 | Django REST framework前后端分离框架实践》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,58人围观)参与讨论

还没有评论,来说两句吧...

Top