DRF开发避坑指南01

news2025/2/28 9:43:34

在当今快速发展的Web开发领域,Django REST Framework(DRF)以其强大的功能和灵活性成为了众多开发者的首选。然而,错误的使用方法不仅会导致项目进度延误,还可能影响性能和安全性。本文将从我个人本身遇到的相关坑来给大家避坑。
在这里插入图片描述

一、API性能优化

坑:响应太慢!!!!!!

import os
from django_filters.rest_framework import DjangoFilterBackend

from rest_framework import viewsets
from rest_framework import filters
from rest_framework import permissions, authentication
from rest_framework.decorators import action
from rest_framework_simplejwt.authentication import JWTAuthentication

from utils.rest_framework_util.pagination import CommonPagination
from utils.rest_framework_util.response import rtn_success_info, rtn_error_info
from utils.rest_framework_util.excel_util import ExcelUtil, write_excel_file
from utils.utils import get_current_time_format
from utils.oss.tx_upload import CommonUpload
from drf_yasg import openapi

__all__ = {
    "CommonViewSet",
    "CommonUserViewSet"
}

from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi

class CommonViewSet(viewsets.ModelViewSet):
    permission_classes = ()
    authentication_classes = ()

    filter_backends = [ DjangoFilterBackend, filters.SearchFilter]

    search_fields = ["id"]
    save_export_folder = "static/save_export/"
    pagination_class = CommonPagination

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        len_model = len(queryset)
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            response_data = {
                "total": len_model,
                "list": serializer.data
            }
            return rtn_success_info(response_data, msg="查询数据成功")
        serializer = self.get_serializer(queryset, many=True)
        return rtn_success_info(serializer.data)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return rtn_success_info(serializer.data)

    def update(self, request, *args, **kwargs):
        """
        put 修改
        """
        try:
            partial = kwargs.pop('partial', False)
            instance = self.get_object()
            serializer = self.get_serializer(instance, data=request.data, partial=partial)
            serializer.is_valid(raise_exception=True)
            self.perform_update(serializer)

            if getattr(instance, '_prefetched_objects_cache', None):
                # If 'prefetch_related' has been applied to a queryset, we need to
                # forcibly invalidate the prefetch cache on the instance.
                instance._prefetched_objects_cache = {}

            return rtn_success_info(serializer.data, msg='修改数据成功')
        except Exception as e:
            return rtn_error_info(msg=e)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return rtn_success_info(msg="数据删除成功")

    def perform_destroy(self, instance):
        instance.delete()

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return rtn_success_info(serializer.data, msg="创建数据成功")

    @action(detail=False, methods=['POST'])
    def data_import(self, request, *args, **kwargs):
        response_data_list = []
        file = request.FILES.get("file", None)
        if file is None:
            return rtn_error_info("需要传入file文件")
        else:
            title_list, data_list = ExcelUtil(file).read_data()
            serializer_class = self.get_serializer_class()
            model = serializer_class.Meta.model
            try:
                if model is not None:
                    model.objects.create()
                    for create_data in data_list:
                        response_data = {}
                        for index_, title in enumerate(title_list):
                            response_data[title] = create_data[index_]
                        if response_data.get('id', None) is not None:
                            response_data.pop("id")
                        serializer = self.get_serializer(data=response_data)
                        if serializer.is_valid():
                            # 创建
                            self.perform_create(serializer)
            except Exception as e:
                return rtn_error_info(f"数据导入失败:{e}")
            response_data_list = data_list
        return rtn_success_info(data=response_data_list, msg='导入数据成功')

    @action(detail=False, methods=['POST'])
    def data_export(self, request, *args, **kwargs):
        id_list = request.data.get('ids', None)
        queryset = self.get_queryset()
        row_data_list = []
        is_first = False
        title_list = []
        title = ""
        for data in queryset:
            title = data.__class__.__name__
            if not is_first:
                data_list = []
                for data_meta in data._meta.fields:
                    data_list.append(data_meta.name)
                    title_list.append(data_meta.name)
                row_data_list.append(data_list)  # title
                is_first = True
                break

        for value_data in queryset.values():
            data_info = []
            if id_list is not None:
                for id_ in id_list:
                    if int(value_data['id']) == int(id_):
                        for title in title_list:
                            data_info.append(value_data[title])
            else:
                for title in title_list:
                    data_info.append(value_data[title])
            if len(data_info) > 0:
                row_data_list.append(data_info)
        excel_file_name = f"{title}_{get_current_time_format('%Y_%m_%d_%H_%M_%S')}.xlsx"
        if not os.path.exists(self.save_export_folder):
            os.makedirs(self.save_export_folder)
        write_excel_file(row_data_list, f"{self.save_export_folder}{excel_file_name}")
        if os.path.exists(f"{self.save_export_folder}{excel_file_name}"):
            url = CommonUpload().cos_upload_file(f"{self.save_export_folder}{excel_file_name}")
            data = {
                'excel_url': url
            }
            return rtn_success_info(data, '导出成功')
        return rtn_error_info("导出失败")


class CommonUserViewSet(CommonViewSet):
    """带用户权限的ViewSet

    Args:
        viewsets (_type_): _description_

    Returns:
        _type_: _description_
    """

    permission_classes = [permissions.IsAuthenticated]
    authentication_classes = [JWTAuthentication, authentication.SessionAuthentication,
                              authentication.BasicAuthentication]

    def create(self, request, *args, **kwargs):
        data = request.data
        data["user"] = request.user.id
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return rtn_success_info(serializer.data, msg="创建数据成功")

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        len_model = len(queryset)
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            response_data = {
                "total": len_model,
                "list": serializer.data
            }
            return rtn_success_info(response_data, msg="查询数据成功")
        serializer = self.get_serializer(queryset, many=True)
        return rtn_success_info(serializer.data)

以这块代码为例,大家会发现一个问题,虽然都封装了ViewSet,但是他的响应速度比之前慢很多,原因何在,问题就出现在len_model = len(queryset)上,因为当前的len(queryset)会遍历每一个model,导致性能缓慢,正确的修改方式是使用queryset.count(),会大幅度的提高性能,直接获取里面的变量。
图片

二、复杂权限管理
针对于这类的权限管理,其实DRF也给咱们弄好了,但是基于实际业务场景的复杂性,本人也提供给大家一个参考的可定制化的代码!
1.通过定制通用类的permissions

class CommonUserViewSet(CommonViewSet):
    """带用户权限的ViewSet

    Args:
        viewsets (_type_): _description_

    Returns:
        _type_: _description_
    """

    permission_classes = [permissions.IsAuthenticated]
    authentication_classes = [JWTAuthentication, authentication.SessionAuthentication,
                              authentication.BasicAuthentication]
 ``
类似这个,这个是用于基础的认证,比方说用户需要登陆才能确认的,使用这个比较方便。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/07b878dcf2d641b79e9700d6a8ade683.png)


2.特定用户
这类的需求,可以通过获取self.request.user来判断,其中可以通过获取用户是否为超级用户,以及username等判断,大大提高drf的灵活性!

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8ddab551e10942f7a1b7ebc0d0dd9686.png)

最后,大家还遇到哪些坑,也可以分享在评论区中,大家一起排雷,祝大家春节喜乐!觉得有用的话可以分享以及关注哈!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2282950.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GD32的GD库开发

所有的Cortex-M处理器都有相同的SysTick定时器,因为CMSIS-Core头文件中定义了一个名为SysTick的结构体。 这个定时器可以用作延时函数,不管是STM32的芯片还是GD32,AT32的芯片,delay函数都可以这么写,只要它是cortex-M…

LabVIEW项目中的工控机与普通电脑选择

工控机(Industrial PC)与普通电脑在硬件设计、性能要求、稳定性、环境适应性等方面存在显著差异。了解这些区别对于在LabVIEW项目中选择合适的硬件至关重要。下面将详细分析这两种设备的主要差异,并为LabVIEW项目中的选择提供指导。 ​ 硬件设…

python如何导出数据到excel文件

python导出数据到excel文件的方法: 1、调用Workbook()对象中的add_sheet()方法 wb xlwt.Workbook() ws wb.add_sheet(A Test Sheet) 2、通过add_sheet()方法中的write()函数将数据写入到excel中,然后使用save()函数保存excel文件 ws.write(0, 0, 1234…

Yocto项目 - 解读CROss PlatformS (CROPS)

一、概述 Yocto项目是一个用于创建自定义Linux发布版本的工具集成项目,在应对复杂应用场景时能提供高度可自定义性。但是在多端机应用中,如何在不同的平台上可靠地完成构建工作?CROss PlatformS (CROPS)即展示了其重要作用。 CROPS是Yocto项…

【技巧】优雅的使用 pnpm+Monorepo 单体仓库构建一个高效、灵活的多项目架构

单体仓库(Monorepo)搭建指南:从零开始 单体仓库(Monorepo)是一种将多个相关项目集中管理在一个仓库中的开发模式。它可以帮助开发者共享代码、统一配置,并简化依赖管理。本文将通过实际代码示例&#xff0…

Ubuntu24.04初始化MySQL报错 error while loading shared libraries libaio.so.1

Ubuntu24.04初始化MySQL报错 error while loading shared libraries: libaio.so.1 问题一:libaio1不存在 # 提示libaio1不存在 [rootzabbix-mysql-master.example.com x86_64-linux-gnu]#apt install numactl libaio1 Reading package lists... Done Building depe…

数据标注开源框架 Label Studio

数据标注开源框架 Label Studio Label Studio 是一个开源的、灵活的数据标注平台,旨在帮助开发者和数据科学家轻松创建高质量的训练数据集。它支持多种类型的数据(如文本、图像、音频、视频等)以及复杂的标注任务(如分类、命名实体…

OS Copilot功能测评:智能助手的炫彩魔法

简介: OS Copilot 是一款融合了人工智能技术的智能助手,专为Linux系统设计,旨在提升系统管理和运维效率。本文详细介绍了在阿里云ECS实例上安装和体验OS Copilot的过程,重点评测了其三个核心参数:-t(模式…

【豆包MarsCode 蛇年编程大作战】蛇形烟花

项目体验地址:项目体验地址 官方活动地址:活动地址 目录 【豆包MarsCode 蛇年编程大作战】蛇形烟花演示 引言 豆包 MarsCode介绍 项目准备 第一步:安装插件 第二步:点击豆包图标来进行使用豆包 使用豆包 MarsCodeAI助手实…

2013年蓝桥杯第四届CC++大学B组真题及代码

目录 1A:高斯日记(日期计算) 2B:马虎的算式(暴力模拟) 3C:第39级台阶(dfs或dp) 4D:黄金连分数(递推大数运算) 5E:前缀…

14.杂谈:领域知识库与知识图谱:概念、关系与重要性

文章目录 1. 领域知识库的概念2. 知识图谱的概念3. 领域知识库与知识图谱的关系与差异3.1 关系3.2 差异 4. 为什么要构建领域知识库?4.1 知识的集中管理与共享4.2 知识的标准化与规范化4.3 促进知识创新与应用 5. 为什么要进行知识融合?5.1 异构数据的整…

【GoLang】利用validator包实现服务端参数校验时自定义错误信息

在C/S架构下,服务端在校验请求参数时,若出现参数错误,要响应给客户端一个错误消息,通常我们会统一响应“参数错误”。 但是,如果只是一味的提示参数错误,我并不知道具体是哪个参数错了呀!能不能…

c#实现重启Explorer.exe并且启动某个命令

由于经常需要重启Explorer.exe 然后接着又需要马上启动一个命令行,于是干脆写一个程序,实现了此功能。 可以直接在运行中,或者在资源管理器中新建任务。 注意,下方的设置为应用程序,可以避免启动时出现黑框。 直接上代…

C语言自定义数据类型详解(一)——结构体类型(上)

什么是自定义数据类型呢?顾名思义,就是我们用户自己定义和设置的类型。 在C语言中,我们的自定义数据类型一共有三种,它们分别是:结构体(struct),枚举(enum),联合(union)。接下来,我…

绘制决策树尝试2 内含添加环境变量步骤

目录 step1 ai码 ai改 step2 下面就是环境配置问题 “ExecutableNotFound: failed to execute WindowsPath(‘dot’), make sure the Graphviz executables are on your systems’ PATH” dot -v愣是没有​编辑 graphviz安装指导 对于Windows用户: 对于Lin…

ChatGPT被曝存在爬虫漏洞,OpenAI未公开承认

OpenAI的ChatGPT爬虫似乎能够对任意网站发起分布式拒绝服务(DDoS)攻击,而OpenAI尚未承认这一漏洞。 本月,德国安全研究员Benjamin Flesch通过微软的GitHub分享了一篇文章,解释了如何通过向ChatGPT API发送单个HTTP请求…

【优选算法】10----无重复字符的最长子串

---------------------------------------begin--------------------------------------- 题目解析: 看到这一类题目,有没有那种一眼就感觉时要用到滑动窗口的感觉,铁子们? 讲解算法原理: 方法一: 暴力解法&#xff…

【模型】RNN模型详解

1. 模型架构 RNN(Recurrent Neural Network)是一种具有循环结构的神经网络,它能够处理序列数据。与传统的前馈神经网络不同,RNN通过将当前时刻的输出与前一时刻的状态(或隐藏层)作为输入传递到下一个时刻&…

开源鸿蒙开发者社区记录

lava鸿蒙社区可提问 Laval社区 开源鸿蒙项目 OpenHarmony 开源鸿蒙开发者论坛 OpenHarmony 开源鸿蒙开发者论坛

C语言中的|=代表啥意思?

在C语言中,| 是复合赋值运算符中的按位或赋值运算符。 其作用是将两个操作数按二进制位进行“或”运算,并将结果赋值给左操作数。例如,若有 x | y;,则等同于 x x | y;。其中,| 是按位或运算符,对两个操作数…