【Python后端开发系列】#2 Django REST Framework (DRF) 接口开发详解(jwt鉴权、orm、自定义分页、接口视图)

【Python后端开发系列】#2 Django REST Framework (DRF) 接口开发详解(jwt鉴权、orm、自定义分页、接口视图)

RoyKe
1年前发布

在正常前后端分离开发中均使用DRF框架进行开发

📕DRF官方文档

快速开发Restful API接口,是对django的改进,更适用于前后端分离开发

myproject/
├── myproject/ 主文件目录(项目设置)
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── apps/ 模块化APP(接口与数据模型)
│   └── user/
│       ├── __init__.py
│       ├── admin.py
│       ├── apps.py
│       ├── models.py
│       ├── tests.py
│       ├── serializers.py
│       ├── urls.py
│       └── views.py
├── ddl/ 存储数据表创建sql脚本
├── utils/ 
│   ├── __init__.py
│   ├── serializers.py # 通用序列化器
│   ├── middleware.py # 中间件 JWT鉴权、日志等
│   ├── request_util.py # 获取请求IP JWT用户信息
│   ├── pagination.py # 自定义分页类
├── config.py 配置文件 填写数据库信息、oauth等配置信息,再在settings.py里调用
├── requirements.txt
├── nginx.conf
└── manage.py

1.安装与配置

    pip install djangorestframework

全局设置引入

    INSTALLED_APPS = [
        'rest_framework',
    ]

2. 创建app

# 直接创建到项目根目录,再迁移到apps目录内
python manage.py startapp myapp
# 或者直接创建子文件项目到apps文件夹内,需要先创建好myapp文件夹
django-admin startapp myapp apps/myapp

注意:需要将setting.py和apps.py应用名均改为apps.myapp

INSTALLED_APPS = [
    ...
    'rest_framework',
    'apps.user',
]
from django.apps import AppConfig

class MyappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'apps.user'

3. 创建模型并迁移

3.1 基于已有数据库,生成数据库表模型(推荐)

📕不同类型数据库的连接方法

  • 设置default数据库mysql配置(其余配置参考文档, 也可以将数据库信息存入config.py,生产部署时再将敏感信息存入环境变量)
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "mydatabase",
        "USER": "mydatabaseuser",
        "PASSWORD": "mypassword",
        "HOST": "127.0.0.1",
        "PORT": "5432",
    }
}
  • 根据数据库自动生成数据模型_使用Django自带inspectdb实现,导出为指定文件_
python manage.py inspectdb > models.py
  • 从models.py里复制对应的表数据模型到对应的app的models.py里

3.2 由django创建管理数据库表格(不推荐)

会产生冗余数据表格,由auth和contenttypes内置组件造成,但并不需要,故不推荐

from django.db import models

# Create your models here.
class User(models.Model):
    username = models.CharField(max_length=100, unique=True)
    email = models.EmailField(unique=True)

    def __str__(self):
        return self.username
python manage.py makemigrations
python manage.py migrate

3.3 自定义auth用户表(鉴权、权限管理)

若需要使用drf自带的auth鉴权与权限管理,可自定义用户数据表

注意:自定义用户数据表必须在数据库迁移前完成,若项目后期修改会增加大量工作量

  1. 自定义用户数据表模型
  2. 在setting中指定用户数据模型

4.序列化与反序列化

序列化: 将 查询集QuerySet (多个模型类的集合)与单个模型类的实例,通过序列化器转化为 json数据(字符串)。

反序列化: 将json格式的字符串数据,通过序列化器转换为Django中的模型类的对象。

4.1 定义序列化器

创建一个名为 serializers.py

序列化会对数据字段进行校验,例如post增加数据时,多格式不符合,则默认返回错误提示

4.1.1 写法1:ModelSerializer 写法

前提:必须已定义数据model,适用于orm连接的数据库

优势:简洁;当不需要自定义校验规则时,可只写meta

from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from .models import User

class UserModelSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(),
    username = serializers.CharField(max_length = 20),
    email = serializers.EmailField(validators=[UniqueValidator(queryset=User.objects.all(),message='邮箱已被注册')])
    class Meta:
        model = User
        fields = ['id', 'username', 'email']
        # fields = '__all__'

4.1.2 写法2:serializer 写法(不常用)

优点:不需要设置好model,不需要在meta指定model,即不使用orm操作的数据库连接

class FiltersSerializer(serializers.Serializer):
    fid = serializers.IntegerField(source='field_code')
    key = serializers.CharField(source='field_en_name')
    name = serializers.CharField(source='field_cn_name')
    rename = serializers.CharField(source='field_rename')
    business_type = serializers.CharField()
    dim_data_type = serializers.CharField()
    group_id = serializers.IntegerField()
    level_index = serializers.IntegerField()
    
    class Meta:
        fields = '__all__'

def get_""

5.分页

drf分页共有三种类型默认分页:

  • PageNumberPagination 简单分页器

查询方式:?page=3 或 ?page=3&size=10(需要)

参数:page, page_size, max_page_size

  • LimitOffsetPagination 偏移分页器

查询方式:?limit=20&offset=100

参数:offset 查询数据起点;limit 每页展示最大数;max_limit 限制最大数量

  • CursorPagination 加密分页器

按照给定的排序方式将数据分页,每一页的分界点是另一页中最后一个数据的主键值。这种方式可以实现更为灵活的分页,因为它不受 limit 的限制,可以方便的实现“_无限滚动式”或“加载更多”_式的交互

注:需要的模型有"created"这个字段,否则要手动指定ordering排序才能进行使用

5.1 自定义分页器

若需要实现?page=3&size=10以及自定义返回样式则需要自定义类

自定义类均存放在common/pagination.py内

from rest_framework.pagination import (
    PageNumberPagination,
    LimitOffsetPagination,
    CursorPagination,
)
from rest_framework.response import Response


class CustomPageNumberPagination(PageNumberPagination):
    """重写PageNumberPagination, 实现ModelViewSet可调用、自定义返回样式、实现size控制"""

    page_size = 10  # 设置默认每页返回数据量
    page_size_query_param = "size"  # 自定义page_size在链接中的参数名称
    max_page_size = 50  # 设置每页最大数据返回量

    # 重写数据分页返回样式
    def get_paginated_response(self, data):
        currentPage = int(self.get_page_number(self.request, self.page.paginator)) or 1
        limit = int(self.get_page_size(self.request)) or 10
        total = self.page.paginator.count if self.page else 0
        return Response(
            {
                "page": currentPage,
                "limit": limit,
                "total": total,
                "results": data,
                "links": {
                    "next": self.get_next_link(),
                    "previous": self.get_previous_link(),
                },
            }
        )


class CustomLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 10
    limit_query_param = "limit"
    offset_query_param = "offset"
    max_limit = 50

class CustomCursorPagination(CursorPagination):
    page_size = 10
    page_size_query_param = "page_size"
    cursor_query_param = "cursor"
    ordering = "id" # 默认采用“created”进行排序,故自定义排序字段

6.ModelViewSet创建视图(常用)

该方法必须使用django自带orm操作方法,同时需要设置好model和序列化

modelvieset方法已经封装好了常用的方法直接封装成了action,默认action如下:

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 更新数据
  • destroy() 删除数据

6.1 接口编写

仅需要配置好model和序列化器,就可直接使用已封装好的五个接口进行增删改查

from rest_framework.viewsets import ModelViewSet
from .models import User
from .serializers import UserModelSerializer
from utils.pagination import CustomPageNumberPagination, CustomLimitOffsetPagination, CustomCursorPagination

class UserModelView(ModelViewSet):
    queryset = User.objects.all().order_by("id")
    serializer_class = UserModelSerializer
    pagination_class = CustomCursorPagination

    # 自定义方法
    def latest(self, request):
        '''获取最后一条记录'''
        # 获取模型数据
        user = User.objects.latest('id')
        # 获取序列化器对象
        s = UserModelSerializer(instance=user)
        return Response(s.data)

6.2 路由配置

由于每个接口只有一个get,故同时使用

urlpatterns = [
    # 常规path
    path('user', UserModelView.as_view({'get':'list', 'post': 'create'})),
    # 正则path,匹配参数(ModelViewSet默认使用pk进行指定数据操作)
    re_path(r'^user/(?P<pk>\d+)$', UserModelView.as_view({'get':'retrieve', 'put': 'update', 'delete': 'destroy'})),
    # 自定义action的路由
    url(r'^user/latest$', views.BookInfoListAPIView.as_view({'get':'latest'})),
]

7.APIView类视图(不常用)

编辑接口

# views.py
from rest_framework import status
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from rest_framework.views import APIView # 使用APIview进行接口开发
from .models import User
from .serializers import UserModelSerializer #调用序列化器
import json

class UserView(APIView):
    """用户查询、增加、修改、删除
    """

    def get(self, request):
        user_id = int(request.query_params.get('id'))
        user = User.objects.get(pk=user_id)
        serializer = UserModelSerializer(user)
        return Response({
            "status": "success",
            "data": serializer.data,
            "msg": "数据获取成功"
            })

    def post(self, request):
        serializer = UserModelSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request):
        data = json.loads(request.body)
        user = User.objects.get(pk=data['id'])
        user.username = data['username']
        user.email = data['email']
        user.save()
        return Response({
            "status": "success",
            "msg": "更新成功"
        })

    def delete(self, request):
        user_id = int(request.query_params.get('id'))
        user = User.objects.get(pk=user_id)
        user.delete()
        return Response({
            "status": "success"
        })
from django.urls import path
from .views import UserView

urlpatterns = [
    path('users', UserView.as_view(), name='user'),
]

8.参数获取

body内容

data = json.loads(request.body)

args

request.query_params.get('id')

附录:

RESTful api 规范

1.请求方式分类

  • 查询 GET
  • 新增 POST
  • 更新 PUT
  • 删除 DELETE

2.设计规范

常见状态代码

1xx:信息性 - 请求已接收,继续处理

2xx:成功 - 请求已成功被服务器接收、理解并接受

3xx:重定向 - 需要进一步的操作以完成请求

4xx:客户端错误 - 请求有语法错误或请求无法实现

5xx:服务器错误 - 服务器在处理请求时发生了错误

常见的状态码包括:

  • 200 OK:请求成功,服务器已经处理并返回了请求的内容。
  • 201 Created:请求已经被实现,且有一个新的资源已经依据请求被创建。
  • 204 No Content:服务器成功处理了请求,但没有返回任何内容。
  • 400 Bad Request:服务器无法处理请求,因为它包含语法错误。
  • 401 Unauthorized:请求需要用户验证。
  • 403 Forbidden:服务器已经理解请求,但是拒绝执行它。
  • 404 Not Found:请求失败,请求的资源在服务器上未找到。
  • 500 Internal Server Error:服务器遇到了不知如何处理的情况。
  • 503 Service Unavailable:服务器暂时无法处理请求,可能是因为超载或维护
©原创版权声明
THE END
喜欢就支持一下吧
点赞 0 分享 收藏
评论 抢沙发
取消
易航博客