DRF开发避坑指南01

在当今快速发展的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)

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DeepSeek R1:中国AI黑马的崛起与挑战

文章目录 技术突破:从零开始的推理能力进化DeepSeek R1-Zero:纯RL训练的“自我觉醒”DeepSeek R1:冷启动与多阶段训练的平衡之道 实验验证:推理能力的全方位跃升基准测试:超越顶尖闭源模型蒸馏技术:小模型的…

电路研究9.2.4——合宙Air780EP中MQTT 相关命令使用方法研究

之前研究了FTP命令,这次研究一下MQTT命令了。 16.14 使用方法举例 9.5.3 MQTT 应用指南 4G 模块支持 MQTT 和 MQTT SSl 协议, MQTT 应用的基本流程如下: 1、如果要支持 SSL,配置 SSL 参数2、通过 TCP 连接到 MQTT 服务器 3、发送 …

寻找旋转数组中的最小元素:C语言实现与分析

在算法与编程的世界里,经常会遇到各种有趣的问题。今天我们来探讨一个经典的题目:寻找旋转数组中的最小元素。我们将通过C语言代码实现,并详细分析其原理和实现细节。 题目描述 给定一个可能旋转过的递增排序数组,找到数组中的最小…

Object类(3)

大家好,今天继续给大家介绍一下object类中的方法,那么话不多说,来看。 hashcode()这个方法,帮我们算了一个具体的对象位置,这里面涉及到数据结构,简单认为它是个内存地址,然后调用Integer.toHexString ()将这个地址以16进制输出。 该方法是一…

Kafka 日志存储 — 磁盘存储

Kafka 依赖与磁盘来存储和缓存消息,采用文件追加的方式来写入消息。顺序写盘的速度快于随机写内存。 1 磁盘存储 除顺序写入外,Kafka中大量使用了页缓存、零拷贝等技术来进一步提升吞吐性能。 1.1 页缓存 页缓存是操作系统实现的一种磁盘缓存&#x…

基于SpringBoot的阳光幼儿园管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

什么是长短期记忆网络?

一、概念 长短期记忆网络(Long Short-Term Memory, LSTM)是一种特殊的循环神经网络(RNN),旨在解决标准RNN在处理长序列时的梯度消失和梯度爆炸问题。LSTM通过引入三个门(输入门、遗忘门和输出门&#xff09…

Unity游戏(Assault空对地打击)开发(1) 创建项目和选择插件

目录 前言 创建项目 插件导入 地形插件 前言 这是游戏开发第一篇,进行开发准备。 创作不易,欢迎支持。 我的编辑器布局是【Tall】,建议调整为该布局,如下。 创建项目 首先创建一个项目,过程略,名字请勿…

996引擎 - NPC-动态创建NPC

996引擎 - NPC-动态创建NPC 创建脚本服务端脚本客户端脚本添加自定义音效添加音效文件修改配置参考资料有个小问题,创建NPC时没有控制朝向的参数。所以。。。自己考虑怎么找补吧。 多重影分身 创建脚本 服务端脚本 Mir200\Envir\Market_Def\test\test001-3.lua -- NPC八门名…

如何看待 OpenAI 的12天“shipmas”发布计划?

openAI的“Shipmas”并非单纯的营销活动,而是在用户增长、技术创新和市场竞争中的综合布局和战略体现。 史上最寒酸的发布会?继十月马斯克在好莱坞电影城高调发布特斯拉三款最新产品(无人出租车、无人巴士、人形机器人)后,十二月,OpenAI CEO 奥特曼宣布 OpenAI 将连续12…

蓝桥杯模拟算法:蛇形方阵

P5731 【深基5.习6】蛇形方阵 - 洛谷 | 计算机科学教育新生态 我们只要定义两个方向向量数组,这种问题就可以迎刃而解了 比如我们是4的话,我们从左向右开始存,1,2,3,4 到5的时候y就大于4了就是越界了&…

第31篇:Python开发进阶:数据可视化与前端集成

第31篇:数据可视化与前端集成 目录 数据可视化概述 什么是数据可视化数据可视化的重要性 Python中的数据可视化库 MatplotlibSeabornPlotlyBokehAltair 数据可视化的基本概念 图表类型设计原则交互性与动态性 与前端框架的集成 前端框架概述Flask与Django集成数据…

240. 搜索二维矩阵||

参考题解:https://leetcode.cn/problems/search-a-2d-matrix-ii/solutions/2361487/240-sou-suo-er-wei-ju-zhen-iitan-xin-qin-7mtf 将矩阵旋转45度,可以看作一个二叉搜索树。 假设以左下角元素为根结点, 当target比root大的时候&#xff…

maven的打包插件如何使用

默认的情况下,当直接执行maven项目的编译命令时,对于结果来说是不打第三方包的,只有一个单独的代码jar,想要打一个包含其他资源的完整包就需要用到maven编译插件,使用时分以下几种情况 第一种:当只是想单纯…

联想拯救者R720笔记本外接显示屏方法,显示屏是2K屏27英寸

晚上23点10分前下单,第二天上午显示屏送到,检查外包装没拆封过。这个屏幕左下方有几个按键,按一按就开屏幕、按一按就关闭屏幕,按一按方便节省时间,也支持阅读等模式。 显示屏是 :AOC 27英寸 2K高清 100Hz…

python:求解偏微分方程(PDEs)

1.偏微分方程基本知识 微分方程是指含有未知函数及其导数的关系式,偏微分方程是包含未知函数的偏导数(偏微分)的微分方程。 偏微分方程可以描述各种自然和工程现象,是构建科学、工程学和其他领域的数学模型主要手段。科学和工程中…

Deepseek技术浅析(二):大语言模型

DeepSeek 作为一家致力于人工智能技术研发的公司,其大语言模型(LLM)在架构创新、参数规模扩展以及训练方法优化等方面都达到了行业领先水平。 一、基于 Transformer 架构的创新 1.1 基础架构:Transformer 的回顾 Transformer 架…

13JavaWeb——SpringBootWeb之事务AOP

1. 事务管理 1.1 事务回顾 在数据库阶段我们已学习过事务了,我们讲到: 事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功&am…

Hive:struct数据类型,内置函数(日期,字符串,类型转换,数学)

struct STRUCT(结构体)是一种复合数据类型,它允许你将多个字段组合成一个单一的值, 常用于处理嵌套数据,例如当你需要在一个表中存储有关另一个实体的信息时。你可以使用 STRUCT 函数来创建一个结构体。STRUCT 函数接受多个参数&…

【Redis】List 类型的介绍和常用命令

1. 介绍 Redis 中的 list 相当于顺序表,并且内部更接近于“双端队列”,所以也支持头插和尾插的操作,可以当做队列或者栈来使用,同时也存在下标的概念,不过和 Java 中的下标不同,Redis 支持负数下标&#x…