Django一分钟:DRF ViewSet烹饪指南,创建好用的视图集

本文将介绍django视图集的内部实现,并带你重写部分代码自己组装强大且趁手的视图集,以满足自定义的业务需求,避免编写大量重复代码。

一、基础知识

Django Rest framework框架允许你将一组相关视图的逻辑组合到一个类中,也就是我们所谓的视图集ViewSet

APIView相比,ViewSet更加抽象,更难理解。APIView的使用方法非常直观,需要你提供诸如.get().post()之类的处理方法,并由其自动将请求分发到对应的方法上。ViewSet则不同,它要求你提供诸如.list().create()这类操作方法,在实现了这些方法之后,使用.as_view()方法请操作方法映射到不同的处理方法上,比如list->getdestroy->delete

一个简单的示例

from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Responseclass UserViewSet(viewsets.ViewSet):"""一个简单的视图集,实现获取用户列表和查询单个用户的功能"""def list(self, request):queryset = User.objects.all()serializer = UserSerializer(queryset, many=True)return Response(serializer.data)def retrieve(self, request, pk=None):queryset = User.objects.all()user = get_object_or_404(queryset, pk=pk)serializer = UserSerializer(user)return Response(serializer.data)

在很多普通业务中,增删改查的操作是相同的,比如请求数据列表的操作,无非是三步:数据库获取查询集->序列化->返回响应。drf预制了这些重复的工作,将通用的方法封装进了ModelViewSet,借助ModelViewSet我们可以非常轻松的完成增删改查等工作(对应APIView就是ModelAPIView):

class AccountViewSet(viewsets.ModelViewSet):"""只需要指定查询集和序列化器即可"""queryset = Account.objects.all()serializer_class = AccountSerializerpermission_classes = [IsAccountAdminOrReadOnly]

ModelViewSet本身不提供这些通用的listcreate之类的方法,而是由一些列Mixin类来实现,ModelViewSet负责把它们组合起来:

class ModelViewSet(mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet):    pass

就以CreateModelMixin为例,CreateModelMixin为我们提供了一个通用的和符合标准的create()方法,其过程也就是获取查询集->序列化->返回,没有特殊需求我们的视图集继承它就能获取预制的create方法,不需要再自己实现:

class CreateModelMixin:"""Create a model instance."""def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):serializer.save()def get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}

细心观察在CreateModelMixin中我们获取序列化器的方法是get_serializer,此外一些其它的Minxin类中,你可能发现其获取查询集的方法是get_queryset或者filter_queryset,还有诸如paginate_queryset这样的方法,一个典型的示例就是ListModelMixin:

class ListModelMixin:"""List a queryset."""def list(self, request, *args, **kwargs):queryset = self.filter_queryset(self.get_queryset())page = self.paginate_queryset(queryset)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)

这些方法并非凭空而来而是由GenericViewSet类来提供,准确说是它的父类GenericAPIView

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):    pass

GenericViewSet继承GenericAPIView为各种Mixin提供统一的获取查询集、序列化器、分页、授权等等接口。

class GenericAPIView(views.APIView):...queryset = Noneserializer_class = None...def get_queryset(self):...def get_object(self):...def get_serializer(self, *args, **kwargs):...def get_serializer_class(self):...def get_serializer_context(self):...def filter_queryset(self, queryset):...def paginator(self):...def paginate_queryset(self, queryset):...def get_paginated_response(self, data):...

二、灵活自定义

drf预制的Mixin足够标准和通用,但如果我们的业务中有特殊需求,我们就需要对drf预制的Mixin重新烹饪,实际操作并不困难,接下来我们通过几个具体的场景来实际体会一下。

自定义响应格式

假如我想让视图集返回的响应遵循如下格式:

{"status": "ok","code": 200,"messages": [],"result": {"user": {"id": 123,"name": "shazow"}}
}

我们可以先实现一个自定义的响应类来替换掉Mixin中使用的响应类。

import json
from rest_framework.response import Responseclass Rep(Response):"""struct json response"""def __init__(self, result=None, message=None, status=None, code=None, **kwargs):if message is None:message = []data = {"status": status,"code": code,"message": message,"result": result}super().__init__(data, code, **kwargs)@staticmethoddef ok(result=None, message=None, code=None, **kwargs):return Rep(result=result, message=message, status="ok", code=code, **kwargs)@staticmethoddef err(result=None, message=None, code=None, **kwargs):return Rep(result=result, message=message, status="err", code=code, **kwargs)

RetrieveModelMixin为例,你可以继承并重写retrieve,也可以干脆复制一份到自己的项目中,再修改retrieve方法,我们这里选择复制一份到自己的项目中。为了和原来的RetrieveModelMixin做区分,且将其命名为XRetrieveModelMixin:

class XRetrieveModelMixin:"""Retrieve a model instance."""# 使用我们自己的Rep响应类替换了Response响应类def retrieve(self, request, *args, **kwargs):try:instance = self.get_object()except Http404:return Rep.err(None, ["查询数据不存在"], status.HTTP_404_NOT_FOUND)serializer = self.get_serializer(instance)return Rep.ok(serializer.data, None, code=status.HTTP_200_OK)# 对比原来的
# class RetrieveModelMixin:
#     """
#     Retrieve a model instance.
#     """
#     def retrieve(self, request, *args, **kwargs):
#         instance = self.get_object()
#         serializer = self.get_serializer(instance)
#         return Response(serializer.data)

自动记录创建和更新数据的用户

细心观察drf的Minxin类并不是将全部分逻辑写在一个create方法或者update方法中,实际上它把实现功能的代码拆分到了多个函数中。

CreateModelMixin类为例,你可以看到create的方法由perform_create方法和get_success_headers组合而来:

class CreateModelMixin:"""Create a model instance."""def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):serializer.save()def get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}

这样非常有利于我们进行重写,假如我们想对serializer.save()的过程做些修改,比如记录创建用户,我们就可以通过重写perform_create来实现:

class TrackerModelViewSet(ModelViewSet):def perform_create(self, serializer):serializer.save(created_by=self.request.user)# 记录更新操作的用户;perform_update来自UpdateModelMixindef perform_update(self, serializer):serializer.save(updated_by=self.request.user)

三、总结

学习drf是如何预制Mixin的,我们可以预制自己的Mixin类和视图集,运用得当我们可以打造属于自己的趁手工具以从大量重复工作中解脱。

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

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

相关文章

PCIe6.0 AIC金手指和板端CEM连接器信号完整性设计规范

先附上我之前写的关于PCIe5.0金手指的设计解读: PCIe5.0的Add-in-Card(AIC)金手指layout建议(一)_pcie cem-CSDN博客 PCIe5.0的Add-in-Card(AIC)金手指layout建议(二)_gnd bar-CSDN博客 首先,相较于PCI…

《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析

目录 一、透视变换 1、什么是透视变换 2、操作步骤 1)选择透视变换的源图像和目标图像 2)确定透视变换所需的关键点 3)计算透视变换的变换矩阵 4)对源图像进行透视变换 5)对变换后的图像进行插值处理 二、轮廓检测…

Python | Leetcode Python题解之第454题四数相加II

题目: 题解: class Solution:def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:countAB collections.Counter(u v for u in A for v in B)ans 0for u in C:for v in D:if -u - v in countAB:ans countAB…

P2480 [SDOI2010] 古代猪文

原题链接 简化题意: 给定 n , G n,G n,G,求 G ∑ d ∣ n C n d m o d 999911659 G^{\sum_{d|n}C_{n}^{d}}mod_{}999911659 G∑d∣n​Cnd​mod​999911659。 发现指数可能非常大,而模数为质数,此时可以考虑运用扩展欧拉定理来化…

网约班车升级手机端退票

背景 作为老古董程序员,不,应该叫互联网人员,因为我现在做的所有的事情,都是处于爱好,更多的时间是在和各行各业的朋友聊市场,聊需求,聊怎么通过IT互联网 改变实体行业的现状,准确的…

k8s实战-2

k8s实战-2 一、Deployment1.多副本2.扩缩容3.自愈&故障转移4.滚动更新5.版本回退 二、Service1.ClusterIP2.NodePort 总结 一、Deployment Deployment 是 k8s 中的一个资源对象,用于管理应用的副本(Pods)。它的主要作用是确保集群中运行…

二分查找一>山脉数组的峰顶索引

1.题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; public int peakIndexInMountainArray(int[] arr) {int left 1, right arr.length-2;while(left < right) {int mid left (right-left1) / 2;if(arr[mid] > arr[mid-1]) left mid;else right mid-1;}ret…

CSP-J/S 复赛算法 背包DP

文章目录 前言背包DP的简介问题描述目标解决方法1. **定义状态**2. **状态转移方程**3. **初始化**4. **目标**举个例子动态规划解决背包问题的核心 DP背包问题示例代码问题描述代码实现核心代码讲解&#xff1a;举例&#xff1a;总结&#xff1a; 总结 前言 背包问题是算法竞…

软件测试:postman详解

一、Postman背景介绍 用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的&#xff0c;用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的css、html、脚本等简单的网…

自然语言处理(NLP):用Python进行情感分析的深入探索

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 前言 随着互联网的发展,社交媒体、产品评价和新闻评论等各种文本数据的涌现,情感分析作为自然语言处理(NLP)领域的一项重要技术,逐渐成为研究和商业应用中的热点之一。情感分析的目标是通过分析文本中的情感…

ubuntu增加swap

ubuntu增加swap 创建myswapfile上电启动 创建myswapfile 首先在你的目录中创建一个myswapfile并创建myswapfile文件&#xff0c;这个名字可以改成你自己的 mkdir myswapfile cd myswapfile/ # 单个为1G&#xff0c;数量为7&#xff0c;总共7g内存 dd if/dev/zero ofswapfile …

更新C语言题目

1.以下程序输出结果是() int main() {int a 1, b 2, c 2, t;while (a < b < c) {t a;a b;b t;c--;}printf("%d %d %d", a, b, c); } 解析:a1 b2 c2 a<b 成立 ,等于一个真值1 1<2 执行循环体 t被赋值为1 a被赋值2 b赋值1 c-- c变成1 a<b 不成立…

【AI大模型-文心-思维树解读-仓颉精通之路-10】

提问&#xff1a;如果是学习一门计算机语言&#xff0c;基于哪种prompt的框架&#xff0c;会得到更好的帮助 回答&#xff1a;如下 版本&#xff1a;文心大模型3.5 在学习一门计算机语言时&#xff0c;为了获得更好的帮助&#xff0c;可以基于以下几种prompt的框架来构建你的学…

如何搭建自己的域名邮箱服务器?Poste.io邮箱服务器搭建教程,Linux+Docker搭建邮件服务器的教程

Linux系统Docker搭建Poste.io电子邮件服务器&#xff0c;搭建属于自己的域名邮箱服务器&#xff0c;可以无限收发电子邮件&#xff08;Email&#xff09;&#xff01; 视频教程&#xff1a;https://www.bilibili.com/video/BV11p1mYaEpM/ 前言 什么是域名邮箱&#xff1f; …

各省份-产业链现代化水平(2001-2022年)

产业链现代化水平是一个综合性指标&#xff0c;它为我们提供了一个多维度的视角来评估各省份在产业链现代化进程中的发展水平。这个指标涵盖了技术创新、产业升级、生产效率、产业结构优化等多个方面&#xff0c;包含原始数据、测算结果以及参考文献。 2001年-2022年各省份-产…

矩阵学习过程中的一些思考

2024.09.27&#xff08;学习鸢尾花书_矩阵力量_Ch20&#xff09; &#xff08;1&#xff09;所有中心过原点的椭圆都可以用一个二维矩阵表示&#xff0c;且特征值表示长短轴长度&#xff0c;特征向量表示长短轴所在方向的单位向量&#xff08;表征椭圆旋转方向&#xff09;&am…

C语言入门基础题(力扣):完成旅途的最少时间(C语言版)

1.题目&#xff1a; 给你一个数组 time &#xff0c;其中 time[i] 表示第 i 辆公交车完成 一趟旅途 所需要花费的时间。 每辆公交车可以 连续 完成多趟旅途&#xff0c;也就是说&#xff0c;一辆公交车当前旅途完成后&#xff0c;可以 立马开始 下一趟旅途。每辆公交车 独立 …

论文翻译 | Generated Knowledge Prompting for Commonsense Reasoning

摘要 整合外部知识是否有利于常识推理&#xff0c;同时保持预训练序列模型的灵活性&#xff0c;这仍然是一个悬而未决的问题。为了研究这个问题&#xff0c;我们开发了生成知识提示&#xff0c;它包括从语言模型生成知识&#xff0c;然后在回答问题时提供知识作为附加输入。我们…

spring揭秘25-springmvc05-过滤器与拦截器区别(补充)

文章目录 【README】【1】springmvc拦截器回顾【1.1】定义与应用【1.2】拦截器作用范围 【2】servlet过滤器回顾【2.1】过滤器定义与应用【2.2】过滤器作用范围 【3】springmvc拦截器与servlet过滤器区别&#xff08;重要*&#xff09;【3.1】拦截方法调用代码实现 【README】 …

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…