django自定义后端过滤
DRF自带的过滤
- 第一个 DjangoFilterBackend 是需要安装三方库见[搜索:多字段筛选]
- 两外两个是安装注册了rest_framework就有。

如上图,只要配置了三个箭头所指的方向,就能使用。
第一个单字段过滤
用户视图集中加上filterset_fields 后,后端搜索过滤就生效了
特点:
- 是准确匹配,如搜王老五,能搜索来,搜老五,是搜不出来的

第二个关键字过滤
配置SearchFilter, 即可实现。就不举例了。
# 后端过滤、搜索与排序filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
现在已经知道使用djangRF 视图集定义的接口,比如列表接口 可以加参数 ?search=xxx , 进行数据的过滤。
第三个排序
也不举例了,见 添加链接描述
这三个的原理
简单总结得说:
- 就是DjangoFilterBackend, SearchFilter, OrderingFilter三个类中有一个filter_queryset的方法, 传入一个querySet,返回过滤后的querySet。
不清楚得看下面源码说明, 接口都使用了 filter_queryset 方法。

而filter_queryset 是GenericAPIView 类中的代码如下:
(大致逻辑:给一个querySet,返回出过滤后的 querySet)
def filter_queryset(self, queryset):"""Given a queryset, filter it with whichever filter backend is in use.You are unlikely to want to override this method, although you may needto call it either from a list view, or from a custom `get_object`method if you want to apply the configured filtering backend to thedefault queryset."""for backend in list(self.filter_backends):queryset = backend().filter_queryset(self.request, queryset, self)return queryset
结合已有知识可知,
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
继续观察上面代码的写法(如下图)

每一项backend后面都.filter_queryset ,
说明SearchFilter 或者 OrderingFilter 和DjangoFilterBackend 这是三个类,且里面都有filter_queryset 的方法:
看源码,果然是 ,它们的filter_queryset 里面就有过滤逻辑:

自定义过滤
针对第一个单字段过滤,修改成模糊匹配
找个地方写py文件,如在utils包下,新建一个取名为filters.py 的文件
import django_filtersfrom system.models import Userclass UsersManageFilter(django_filters.rest_framework.FilterSet):"""用户管理 简单过滤器URL格式:http://127.0.0.1:8100/?start_time=2022-10-02 08:00:00&end_time=2023-12-31 23:59:59"""# 1.创建时间从start_time = django_filters.DateTimeFilter(field_name='create_datetime', lookup_expr='gte')# 2.创建时间到end_time = django_filters.DateTimeFilter(field_name='create_datetime', lookup_expr='lte')# 3.用户名-模糊搜索username = django_filters.CharFilter(field_name='username', lookup_expr='icontains')# 4.姓名号码-模糊搜索realname = django_filters.CharFilter(field_name='mobile', lookup_expr='icontains')class Meta:model = Userfields = []
在到视图集下,写 filterset_class即可生效。

除了改成模糊支持模糊搜索,还可以比如根据某个字段的时间范围来过滤等等
具体可以搜索 :django_filters如何使用
根据原理自己写一个过滤类,比如实现数据过滤
同样在filters.py中, 自定义一个类,需要继承BaseFilterBackend,写一个filter_queryset方法即可、 里面就可以写根据用户角色,角色的权限来返回不同的数据了

同时,视图集中,在filter_backends中,要加上这个类。

这里先写一个简单易懂的例子,试试
- 根据登录用户,超级管理员就返回所有的数据
- 非超级管理员,假设只能看见自己创建的数据
from rest_framework.filters import BaseFilterBackend
class DataPermissionFilter(BaseFilterBackend):def filter_queryset(self, request, queryset, view):# 1.超级管理员,返回所有数据if request.user.is_superuser == 0:# 2.非超级管理管理,还要进行判断# 获取用户iduser_id = getattr(request.user, 'id', None)# 返回创建者 登录人自己创建的数据return queryset.filter(creator=user_id)else:return queryset
验证:为非超级管理员时


为超级管理员时,就返回的全部

-
以上是一个简单的例子。是根据queryset中的创建人来的,
首先要满足你所查询的querySet是拥有创建人这个字段的。 -
复杂点的逻辑一,可以是根据用户拥有的角色,角色又拥有哪些数据,
假如
A角色关联的是 1公司,2公司数据,
B角色关联的是 2公司,3公司数据
当查询某种数据时,对应的模型也就需要有公司字段。
3.复杂点的逻辑二, 可以是根据用户拥有的角色,角色又拥有部门,
要查询的数据也拥有部门,实现了数据权限
角色模型如下:

业务模型:
如这个Project项目模型,它是存在depart_id的。

另外:序列化器基类中,重写了create方法,比如,在新建一个 project时,该数据的depart_id,字段就是当前用户的数据。

过滤类的写法如下:
主要解析:
- 用户是超级管理员, 就 所有数据不过滤
- 用户(部门id,和角色是必有的,但也要考虑无),根据用户角色们,如果其中有个角色的 data_range为3, 或者有个角色为 管理员admin, 就是 所有数据 不过滤
- 根据用户角色们,如果角色们的data_range没有3, 有 data_range为0,那么就 会查业务数据的
creator为当前用户的数据,且depart_id 为自己部门的数据, 业务数据没有depart_id也能查 - 根据用户角色们,如果角色们的data_range没有3和0,那就是124, 就会查业务数据
depart_id满足的数据
以下代码现有逻辑:当存在多个角色,一个角色为0 仅本人数据, 一个角色为1本部门数据时, 会优先满足0 的情况
此代码仅做参考,
- 因为还没解决仅本人数据,和 本部门数据同时存在的矛盾。、
- 业务数据是哪个部门的人创建,就属于哪个部门的数据(创建业务数据时,depart_id的存值(上面那张图)),如果业务中,要求各个部门只看自己部门的数据,才有存在的价值
"""
@Remark: 自定义过滤器
"""
from rest_framework.filters import BaseFilterBackend
from system.models import Depart
import django_filters
from system.models import Userclass DataLevelPermissionsFilter(BaseFilterBackend):"""功能:《数据级权限过滤器》,步骤如下:第一步. 当前用户为超级管理员,则返回所有数据第二步. 获取用户所属部门的id,没有部门则返回空数据第三步. 判断用户是否分配角色,没有则返回空数据第四步. 获取用户所有角色的数据权限列表(会有多个角色,进行去重)------> 得到 data_permissions_list,如:[0, 1, 2,4 ],其中0表示本人数据,1表示本部门数据,2表示本部门及以下数据, (3 添加不进来的)第五步. 仅访问本人数据(考虑到部门可能会变更,所以再添加当前部门条件)------如果有0,仅本人数据,就不管有 有角色为124 的数据权限(因为已经提前返回了)第六步. 判断业务模型是否有部门ID字段(depart_id),没有返回所有数据第七步. 根据各个角色的数据权限部门并集,返回对应部门的数据"""def filter_queryset(self, request, queryset, view):# 1.超级管理员,返回所有数据if request.user.is_superuser == 0:# 2. 获取用户所属部门id,没有部门,则返回None(无数据)depart_id = getattr(request.user, 'depart_id', None)if not depart_id:return queryset.none()# 3. 判断用户是否分配角色,没有则仅返回【空】if not hasattr(request.user, 'role'):return queryset.none()# return queryset.filter(depart_id=depart_id) 本部门的数据# 4. 获取用户的所有角色列表,得到【数据】范围列表(如:本人数据、本部门数据、本部门及以下数据等)role_list = request.user.role.filter(status=1).values('admin', 'data_range')data_permissions_list = []for ele in role_list:# 4.1 全部数据(3)或者角色为管理员,则返回全部数据if 3 == ele.get('data_range') or ele.get('admin') == True:return querysetdata_permissions_list.append(ele.get('data_range'))# 4.2 得到所有角色无重复的【数据权限】列表data_permissions_list = list(set(data_permissions_list)) # 可能是 [0, 1, 2,4]# 5. 仅访问本人数据(考虑到部门可能会变更,所以再添加当前部门条件)if 0 in data_permissions_list:if not getattr(queryset.model, 'depart_id', None):return queryset.filter(creator=request.user)else:# 换部门了,就不能访问原来部门的数据return queryset.filter(creator=request.user, depart_id=depart_id) # (创建人是当前用户,查询的数据是当前部门的数据)# 6. 判断业务模型是否有部门ID字段(depart_id),没有返回所有数据if not getattr(queryset.model, 'depart_id', None):return queryset# 7. 处理:1=本部门数据、2=本部门及以下数据、4=自定数据权限 的情况depart_list = []for data_range in data_permissions_list:if data_range == 4: # 6.1 自定义数据权限(读取role里面的depart部门)depart_list.extend(request.user.role.filter(status=1).values_list('depart__id', flat=True))elif data_range == 2: # 6.2 本部门及以下数据权限depart_list.extend(get_depart(depart_id, ))elif data_range == 1: # 6.3 本部门数据权限depart_list.append(depart_id)return queryset.filter(depart_id__in=list(set(depart_list)))else:return queryset# 没用到
class UsersManageFilter(django_filters.rest_framework.FilterSet):"""用户管理 简单过滤器URL格式:http://127.0.0.1:8100/?start_time=2022-10-02 08:00:00&end_time=2023-12-31 23:59:59"""# 1.创建时间从start_time = django_filters.DateTimeFilter(field_name='create_datetime', lookup_expr='gte')# 2.创建时间到end_time = django_filters.DateTimeFilter(field_name='create_datetime', lookup_expr='lte')# 3.用户名-模糊搜索username = django_filters.CharFilter(field_name='username', lookup_expr='icontains')# 4.手机号码-模糊搜索mobile = django_filters.CharFilter(field_name='mobile', lookup_expr='icontains')class Meta:model = Userfields = []def get_depart(depart_id, depart_all_list=None, depart_list=None):"""递归获取部门的所有下级部门:param depart_id: 需要获取的部门id:param depart_all_list: 所有部门列表:param depart_list: 递归部门list:return:"""if not depart_all_list:depart_all_list = Depart.objects.all().values('id', 'parent')if depart_list is None:depart_list = [depart_id]for ele in depart_all_list:if ele.get('parent') == depart_id:depart_list.append(ele.get('id'))get_depart(ele.get('id'), depart_all_list, depart_list)return list(set(depart_list))
使用自定义类
方式1 笨办法:在新的视图集中,重写filter_backends, 把自定义的类装到列表里即可

方式2 : 假如已经定义了视图集基类
并且在继承视图集基类后,不想重写filter_backends

就可以这样:
在基类写一个other_backends, 并重写filter_queryset

# 6.重写filter_queryset方法-后端过滤器并集(搜索过滤和并数据过滤)def filter_queryset(self, queryset):# 取filter_backends 和 other_filter_backends 的无重复并集,data_filter_backends有可能是Nonefor backend in set(set(self.filter_backends) | set(self.other_backends or [])):queryset = backend().filter_queryset(self.request, queryset, self)return queryset
在具体的视图集中,这样写就实现了

相关文章:
django自定义后端过滤
DRF自带的过滤 第一个 DjangoFilterBackend 是需要安装三方库见[搜索:多字段筛选]两外两个是安装注册了rest_framework就有。 如上图,只要配置了三个箭头所指的方向,就能使用。 第一个单字段过滤 用户视图集中加上filterset_fields …...
计算机网络Day03--物理层
信道复用技术 频分复用 时分复用 统计时分复用 频分复用(FDM) 最基本 将整个宽带分为多份,用户在分配到一定的频带后,在通信过程中自始至终都使用这个频带 所有的用户在同一时间占用不同的带宽资源,以并行的方式工…...
RabbitMQ节点故障的容错方案
RabbitMQ节点故障的容错方案 1. broker启动加载逻辑1.1 日志文件1.2 broker启动流程1.2.1 整体流程1.2.2 数据恢复流程 2. 队列高可用2.1 选主逻辑2.1.1 从节点晋升策略2.1.2 主队列选择策略 2.2 HA切换 3. 疑问和思考3.1 如果一个broker宕机,运行在broker上的队列数…...
瑞_Redis_初识Redis(含安装教程)
文章目录 1 初识Redis1.1 认识NoSQL1.1.1 结构化与非结构化1.1.2 关联和非关联1.1.3 查询方式1.1.4 事务1.1.5 总结 1.2 认识Redis1.2.1 介绍1.2.2 特征1.2.3 优势 1.3 安装Redis ★★★1.3.1 Linux安装Redis1.3.1.1 安装Redis依赖 1.3.2 Windows安装Redis1.3.2.1 安装步骤1.3.…...
Android进阶(二十九) 走近 IntentFilter
文章目录 一、什么是IntentFilter ?二、IntentFilter 如何过滤隐式意图?2.1 动作测试2.2 类别测试2.3 数据测试 一、什么是IntentFilter ? 如果一个 Intent 请求在一片数据上执行一个动作, Android 如何知道哪个应用程序…...
vue+element下日期组件momentjs转换赋值问题
记录下使用momentjs转换日期字符串赋值给element的日期组件报错问题; <el-date-pickerv-model"form.serviceTime"type"date"class"fill-w mar-t-xs"value-format"yyyy-MM-dd HH:mm:ss"placeholder"请选择日期&quo…...
普源(RIGOL) DHO914S示波器 简单开箱评测
普源精电(RIGOL) DHO914S 12bit数字示波器 简单开箱评测。 旧的示波器感觉不好用,所以换个新的,看中了普源的这款,主要看中它便携支持PD供电,还有伯德图功能,以及12bit的垂直分辨率。如果你对我上面说的点没需求&…...
docker 安装Oracle19c
一、下载镜像 docker pull registry.cn-hangzhou.aliyuncs.com/zhuyijun/oracle:19c通过docker images 命令查看 如下图:已经有oracle 19c镜像。 二、创建挂载文件 # 创建文件 mkdir -p /home/data/oracle/oradata# 授权,不授权会导致后面安装失败 c…...
qt-OPENGL-星系仿真
qt-OPENGL-星系仿真 一、演示效果二、核心程序三、下载链接 一、演示效果 二、核心程序 #include "model.h"Model::Model(QOpenGLWidget *_glWidget) { glWidget _glWidget;glWidget->makeCurrent();initializeOpenGLFunctions(); }Model::~Model() {destroyV…...
Java实战:Spring Boot实现AOP记录操作日志
本文将详细介绍如何在Spring Boot应用程序中使用Aspect Oriented Programming(AOP)来实现记录操作日志的功能。我们将探讨Spring Boot集成AOP的基本概念,以及如何使用Spring Boot实现AOP记录操作日志。最后,我们将通过一个具体示例…...
C++ //练习 7.38 有些情况下我们希望提供cin作为接受istream参数的构造函数的默认实参,请声明这样的构造函数。
C Primer(第5版) 练习 7.38 练习 7.38 有些情况下我们希望提供cin作为接受istream&参数的构造函数的默认实参,请声明这样的构造函数。 环境:Linux Ubuntu(云服务器) 工具:vim 代码块 Sa…...
算法:两数之和
算法:两数之和 方法一:暴力法 function twoSum(nums, target) {for (let i 0; i < nums.length; i) {for (let j i 1; j < nums.length; j) {if (nums[i] nums[j] target) {return [i, j];}}}return null; }方法二:哈希表 func…...
pytorch: ground truth similarity matrix
按照真实标签排序pair-wise相似度矩阵的Pytorch代码 本文仅作留档,用于输出可视化 Inputs: Ground-truths Y ∈ R n 1 \mathbf{Y}\in\mathbb R^{n\times 1} Y∈Rn1, Similarity matrix A ∈ R n n \mathbf{A}\in\mathbb R^{n\times n} A∈RnnOutputs: Block dia…...
鸿蒙 gnss 开关使能流程
先WiFi,后 定位,再从蓝牙到NFC,这个就是我大致熟悉开源鸿蒙代码的一个顺序流程,WiFi 的年前差不多基本流程熟悉了,当然还有很多细节和内容没有写到,后续都会慢慢的丰富起来,这一篇将开启GNSS的篇…...
设计模式-创建型模式-抽象工厂模式
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。 由于工厂方法模式中的每个工厂只生产一类产品&…...
【Go】五、Grpc 的入门使用
grpc 与 protobuf grpc 使用的是 protobuf 协议,其是一个通用的 rpc 框架,基本支持主流的所有语言、其底层使用 http/2 进行网络通信,具有较高的效率 protobuf 是一种序列化格式,这种格式具有 序列化以及解码速度快(…...
PDF加粗内容重复读取解决方案
文章目录 前言发现问题解决方案问题分析大致逻辑 show my code 前言 在使用pdfplumber读取PDF的过程中,由于加黑的内容会被莫名其妙的读取两次,带来了很大的困扰。这篇文章将给出解决方案。 发现问题 在在使用pdfplumber读取PDF的过程中,读…...
Golang 并发 Channel的用法
目录 Golang 并发 Channel的用法1. channel 的创建2. nil channel读写阻塞示例close示例 3. channel 的读写4. channel 只读只写5. 关闭channelchannel关闭后,剩余的数据能否取到读取关闭的channel,将获取零值使用ok判断,是否关闭使用for-ran…...
cfa复习资料介绍之二:notes(SchweserNotes)
什么是CFA notes? CFA资料Study Notes都是外国一些出版机构针对CFA考试提供的复习资料,而其中Schweser在国内的名气最大,用的人也最多。内容详尽并且突出重点,并且CFA Notes的内容相比于官方curriculum教材更加符合中国CFA考生的心态&#x…...
FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,可以用标准 FITC 滤光片组进行成像
FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,可以用标准 FITC 滤光片组进行成像 您好,欢迎来到新研之家 文章关键词:FITC Palmitate Conjugate,FITC-棕榈酸酯缀合物,FITC 棕榈酸酯缀合物,F…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
