我々は望む、七つの嘆きを。|

园龄:粉丝:关注:

2023-08-09 14:49阅读: 26评论: 0推荐: 0

DRF

0x01 概述

  • DRF 是 Django REST Framework 的缩写,有利于实现前后端分离项目(Django 基础

    • DRF 官网链接
    • DRF 相关包
      • coreapi:自动生成 API 文档
      • Markdown:解析 Markdown 语法
      • Pygments:语法高亮
      • django-filter:支持 Django 过滤器
      • django-guardian:实现 DRF 对象级权限控制
  • 前后端分离

    • 交互形式

      HTTP Method

      JSON or XML

      前端/客户端

      RESTful API

      后端/服务器

    • 开发模式

      提出需求

      约定接口规范和数据格式

      前后端并行开发

      前后端对接

      前端调试效果

      集成

      交付

    • 数据接口规范

      定制接口
      确定规范

      前端开发
      模拟数据

      连调
      校验格式

      提测
      自动化测试

      后端开发
      数据自测

  • Restful API 最佳实践详解

    协议、域名、版本、路径、HTTP 动词、过滤信息、状态码、错误处理、返回结果、Hypermedia API

0x02 创建项目

  • 创建 Django 项目

    • 创建流程

    • 修改 settings.py

      ALLOWED_HOSTS = ['*']
      # ...
      STATIC_ROOT = os.path.join(BASE_DIR, "static")
      STATICFILES_DIRS = [
      os.path.join(BASE_DIR, "staticfiles")
      ]
  • 安装 DRF

    • pip install djangorestframework
  • 在 settings.py 中配置 DRF

    INSTALLED_APPS = [
    # ...
    'rest_framework',
    'rest_framework.authtoken',
    ]
    # ...
    REST_FRAMEWORK = {
    # 分页器
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 50,
    # 时间字段
    'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',
    # Response 对象参数
    'DEFAULT_RENDER_CLASSES': [
    'rest_framework.renders.JSONRenderer',
    'rest_framework.renders.BrowsableRenderer',
    ],
    # Request 解析器
    'DEFAULT_PARSER_CLASSES': [
    'rest_framework.parsers.JSONParser',
    'rest_framework.parsers.FormParser',
    'rest_framework.parsers.MultiPartParser',
    ],
    # 权限
    'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.IsAuthenticated',
    ],
    # 认证
    'DEFAULT_AUTHENTICATION_CLASSES': [
    'rest_framework.authentication.BasicAuthentication',
    'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.TokenAuthentication',
    ]
    }
  • 在 ./urls.py 配置根路由

    from django.urls import path, include
    urlpatterns = [
    path('api/', include('rest_framework.urls')),
    ]

0x03 添加模型

  • 在 models.py 中创建新模型

    from django.db import models
    class User(models.Model):
    username = models.CharField(max_length=30, unique=True)
    password = models.CharField(max_length=255)
    age = models.IntegerField(default=0)
    class Meta:
    verbose_name = '用户表'
    verbose_name_plural = verbose_name
    ordering = ('age',)
    def __str__(self):
    return self.username
  • 在 admin.py 中配置模型

    from django.contrib import admin
    from App.models import *
    @admin.register(User)
    class UserAdmin(admin.ModelAdmin):
    # 需要显示的字段
    list_display = ('username', 'password', 'age')
    # 可以搜索的字段
    search_fields = list_display
    # 需要过滤的字段
    list_filter = list_display

0x04 序列化

  • 序列化:将 Django 的 queryset 数据或 instance 数据转换为 JSON 数据

    • 反序列化:将 JSON 数据转换为 queryset 数据或 instance 数据
  • 序列化作用:

    • 验证处理 request.data
    • 验证器的参数
    • 同时序列化多个对象
    • 序列化过程中添加上下文
    • 对无效的数据进行异常处理
  • 继承序列化模型类 ModelSerializer

    • 在 App 目录下新建 serializers.py

      from rest_framework import serializers
      from App.models import *
      class UserSerializer(serializers.ModelSerializer):
      # 外键字段
      foreignKeyName = serializers.ReadOnlyField(source='Table.Key')
      class Meta:
      model = User
      # 排除指定字段
      # exclude = ('id',)
      # 设置需要显示的字段
      fields = '__all__'
      # 指定遍历深度
      depth = 2
  • 实现携带 URL 的 HyperlinkedModelSerializer

    • 修改 serializers.py

      class UserSerializer(serializers.HyperlinkedModelSerializer):
      class Meta:
      model = User
      # url 参数名是默认值,可在 settings.py 的 URL_FIELD_NAME 中修改
      fields = ('url',)

0x05 API 接口开发

(1)RESTful API 接口

  • 在 App/views.py 中,RESTful API开发方法

    • Function Based View,FBV 函数式编程,Django 原生方法

      import json
      from django.http import HttpResponse, JsonResponse
      from django.views.decorators.csrf import csrf_exempt
      @csrf_exempt
      def user_list(request):
      datas = {
      'username': '111',
      'age': '20'
      }
      if request.method == 'GET':
      return JsonResponse(datas)
      if request.method == 'POST':
      user = json.loads(request.body.decode('utf-8'))
      return HttpResponse(json.dumps(user), content_type='application/json')
      • 装饰器 csrf_exempt 用于对 POST 请求取消 CSRF 的限制
    • Classed Based View,CBV 类视图

      import json
      from django.http import HttpResponse, JsonResponse
      from django.views.decorators.csrf import csrf_exempt
      from django.views import View
      class UserList(View):
      def get(self, request):
      datas = {
      'username': '111',
      'age': '20'
      }
      return JsonResponse(datas)
      @csrf_exempt
      def post(self, request):
      user = json.loads(request.body.decode('utf-8'))
      return HttpResponse(json.dumps(user), content_type='application/json')
      • 思路:对不同的请求方法,用对于的函数处理

      • 对于装饰器的使用可以放在类外:

        from django.utils.decorators import method_decorator
        @method_decorator(csrf_exempt, name='dispatch')
        class UserList(View):
        def get(self, request):
        # ...
        def post(self, request):
        # ...
    • Generic Classed Based View,GCBV 通用类视图

    • viewsets,DRF 视图集

(2)FBV

装饰器 api_view

  • views.py

    from rest_framework.decorators import api_view
    from rest_framework.response import Response
    from rest_framework import status
    from App.models import *
    from App.serializers import *
    @api_view(["GET", "POST"])
    def user_list(request):
    if request.method == "GET":
    userSerializer = UserSerializer(instance=User.objects.all(), many=True)
    return Response(data=userSerializer.data, status=status.HTTP_200_OK)
    elif request.method == "POST":
    userSerializer = UserSerializer(data=request.data, partial=True)
    if userSerializer.is_valid():
    userSerializer.save()
    return Response(data=userSerializer.data, status=status.HTTP_201_CREATED)
    return Response(userSerializer.errors, status=status.HTTP_400_BAD_REQUEST)
    • 对信息进行获取、更新、删除

      @api_view(["GET", "PUT", "DELETE"])
      def user_detail(request, pk):
      try:
      user = User.objects.get(pk=pk)
      except User.DoesNotExist:
      return Response(data={"msg": "Not Exist"}, status=status.HTTP_404_NOT_FOUND)
      else:
      if request.method == "GET":
      serializer = UserSerializer(instance=user)
      return Response(data=serializer.data, status=status.HTTP_200_OK)
      elif request.method == "PUT":
      serializer = UserSerializer(instance=user, data=request.data)
      if serializer.is_valid:
      serializer.save()
      return Response(data=serializer.data, status=status.HTTP_200_OK)
      return Response(data=serializer.data, status=status.HTTP_400_BAD_REQUEST)
      elif request.method == "DELETE":
      user.delete()
      return Response(status=status.HTTP_204_NO_CONTENT)
  • 子路由 App/urls.py

    from django.urls import path, include
    from App.views import *
    urlpatterns = [
    path('fbv/list/', user_list, name='userList'),
    path('fbv/detail/<int:pk>/', user_detail, name='userDetail'),
    ]
  • 根路由 ./urls.py

    from django.urls import path, include
    urlpatterns = [
    path('user/', include('App.urls'))
    ]

(3)CBV

需要导入 APIView

  • views.py

    from rest_framework.views import APIView
    class UserList(APIView):
    def get(self, request):
    queryset = User.objects.all()
    serializer = UserSerializer(instance=queryset, many=True)
    return Response(serializer.data, status=status.HTTP_200_OK)
    def post(self, request):
    serializer = UserSerializer(data=request.data)
    if serializer.is_valid():
    serializer.save(user = self.request.user)
    return Response(data=serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    • 对信息进行获取、更新、删除

      class UserDetail(APIView):
      @staticmethod
      def get_object(pk):
      try:
      return User.objects.all(pk=pk)
      except User.DoesNotExist:
      return
      def get(self, request, pk):
      obj = self.get_object(pk)
      if not obj:
      return Response(data={"msg": "Not Exist"}, status=status.HTTP_404_NOT_FOUND)
      serializer = UserSerializer(instance=obj)
      def put(self, request, pk):
      obj = self.get_object(pk)
      if not obj:
      return Response(data={"msg": "Not Exist"}, status=status.HTTP_404_NOT_FOUND)
      serializer = UserSerializer(instance=obj)
      if serializer.is_valid():
      serializer.save()
      return Response(data=serializer.data, status=status.HTTP_201_CREATED)
      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      def delete(self, request, pk):
      obj = self.get_object(pk)
      if not obj:
      return Response(data={"msg": "Not Exist"}, status=status.HTTP_404_NOT_FOUND)
      obj.delete()
      return Response(status=status.HTTP_204_NO_CONTENT)
  • 子路由 App/urls.py

    from django.urls import path
    from App import views
    urlpatterns = [
    path('cbv/list/', views.UserList.as_view(), name='userList'),
    path('cbv/detail/<int:pk>', views.UserDetail.as_view(), name='userDetail'),
    ]

(4)Generic Classed Based View

需要导入 generics

  • views.py

    from rest_framework import generics
    class GUserList(generics.ListCreateAPIView):
    # 变量名继承于 generics,名称固定
    queryset = User.objects.all()
    serializer_class = UserSerializer
    # 重写方法
    def perform_create(self, serializer):
    serializer.save(user=self.request.user)
  • 子路由 App/urls.py

    from App import views
    urlpatterns = [
    path('gcbv/list/', views.GUserList.as_view(), name='userList'),
    path('gcbv/detail/<int:pk>', views.GUserDetail.as_view(), name='userDetail'),
    ]

(5)viewsets

  • views.py

    from rest_framework import viewsets
    class UserViewSet(viewsets.ModelViewSet):
    # 忽略权限、认证、限流等操作
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def perform_create(self, serializer):
    serializer.save(user=self.request.user)
  • 子路由 App/urls.py

    • 方法一

      from App import views
      urlpatterns = [
      path('viewsets/', views.UserViewSet.as_view(
      # 传入字典,key 为 HTTP 方法,value 为视图集的 Mixin 中的方法
      {"get": "list", "post": "create"}
      ), name='userViewSetList'),
      path('viewsets/<int:pk>/', views.UserViewSet.as_view(
      # put:全部更新
      # patch:部分更新
      {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destory"}
      ), name='userViewSetDetail'),
      ]
    • 方法二

      from django.urls import path, include
      from App import views
      from rest_framework.routers import DefaultRouter
      router = DefaultRouter()
      router.register(prefix="viewsets", viewset=views.UserViewSet)
      urlpatterns = [
      path("", include(router.urls))
      ]

0x06 认证与权限

认证:用户登录的身份信息校验

权限:已登录用户访问接口的校验

(1)认证方式

  • BasicAuthentication
    • 基本账号密码验证,适用于测试开发环境,不建议用于生产环境
  • SessionAuthentication
    • 使用基本 Django 后端会话验证,需要 CSRF_Token
  • TokenAuthentication

(2)Token 生成

  • 在 settings.py 中进行配置

    INSTALLED_APPS = [
    'rest_framework.authtoken',
    ]
  • 在 views.py 中

    • 生成 Token

      # 信号
      from django.db.models.signals import post_save
      # 接收
      from django.dispatch import receiver
      # 模型
      from django.conf import settings
      from rest_framework.authtoken.models import Token
      @receiver(post_save, sender=settings.AUTH_USER_MODEL)
      def generate_token(sender, instance=None, created=False, **kwargs):
      if created:
      Token.objects.create(user=instance)
    • 绑定认证方式

      from rest_framework.decorators import api_view, authentication_classes
      from rest_framework.authentication import BasicAuthentication
      @authentication_classes((BasicAuthentication, ))
      def user_list(request):
      # ...
  • 在根路由 urls.py 中配置路由

    from rest_framework.authtoken import views
    urlpatterns = [
    # 获取 Token 的接口
    path('api-token-auth/', views.obtain_auth_token),
  • 使用 POST 方法获取 Token

(3)权限控制

a. 常用的权限类与使用

  • 常见权限类

    • IsAuthenticatedOrReadOnly:已登录可以增删改查,未登录仅可查询
    • IsAuthenticated:已登录可以增删改查,未登录不允许任何操作
    • IsAdminUser:仅管理员请求
    • AllowAny:允许任何请求
  • 使用

    • views.py

      from rest_framework.decorators import permission_classes
      from rest_framework.permissions import IsAuthenticated
      # FBV
      @permission_classes((IsAuthenticated, ))
      def user_list(request):
      # ...
      # GCBV
      class GUserList(generics.ListCreateAPIView):
      permission_classes = IsAuthenticated

b. 自定义对象级别权限

  • 新建文件 App/permission.py

    from rest_framework import permissions
    class IsOwnerReadOnly(permissions.BasePermission):
    # 仅允许对象的所有者进行编辑,其他人只读
    def has_object_permission(self, request, view, obj):
    if request.method in permissions.SAFE_METHODS:
    return True
    return request.user == obj.user
  • 导入 views.py

    from App.permission import IsOwnerReadOnly
    class GUserDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)

0x07 API 接口文档

(1)生成

  • 安装 pyyaml、uritemplate

  • settings.py

    REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
    }
  • 根路由 urls.py

    from rest_framework.schemas import get_schema_view
    # 视图概要
    schema_view = get_schema_view(title="API DOCUMENTATION", description="DRF")
    urlpatterns = [
    path('schema/', schema_view),
    ]

(2)配置 coreapi

  • 安装 coreapi

  • 修改 settings.py

    REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
    }
  • 修改根路由 urls.py

    from rest_framework.documentation import include_docs_urls
    urlpatterns = [
    path('docs/', include_docs_urls(title="API DOCUMENTATION", description="DRF")),
    ]

-End-

本文作者:SRIGT

本文链接:https://www.cnblogs.com/SRIGT/p/17616848.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   SRIGT  阅读(26)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起