求个没封的w站2021你懂,有账号密码网站怎么建设,汽车软件开发流程,免费制作微信小程序软件
DRF自带的过滤
第一个 DjangoFilterBackend 是需要安装三方库见[搜索#xff1a;多字段筛选]两外两个是安装注册了rest_framework就有。
如上图#xff0c;只要配置了三个箭头所指的方向#xff0c;就能使用。
第一个单字段过滤
用户视图集中加上filterset_fields …
DRF自带的过滤
第一个 DjangoFilterBackend 是需要安装三方库见[搜索多字段筛选]两外两个是安装注册了rest_framework就有。
如上图只要配置了三个箭头所指的方向就能使用。
第一个单字段过滤
用户视图集中加上filterset_fields 后后端搜索过滤就生效了
特点
是准确匹配如搜王老五能搜索来搜老五是搜不出来的
第二个关键字过滤
配置SearchFilter 即可实现。就不举例了。 # 后端过滤、搜索与排序filter_backends [DjangoFilterBackend, SearchFilter, OrderingFilter] 现在已经知道使用djangRF 视图集定义的接口比如列表接口 可以加参数 ?searchxxx , 进行数据的过滤。
第三个排序
也不举例了见 添加链接描述
这三个的原理
简单总结得说:
就是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_objectmethod 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_time2022-10-02 08:00:00end_time2023-12-31 23:59:59# 1.创建时间从start_time django_filters.DateTimeFilter(field_namecreate_datetime, lookup_exprgte)# 2.创建时间到end_time django_filters.DateTimeFilter(field_namecreate_datetime, lookup_exprlte)# 3.用户名-模糊搜索username django_filters.CharFilter(field_nameusername, lookup_expricontains)# 4.姓名号码-模糊搜索realname django_filters.CharFilter(field_namemobile, lookup_expricontains)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(creatoruser_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_iddepart_id) 本部门的数据# 4. 获取用户的所有角色列表得到【数据】范围列表如:本人数据、本部门数据、本部门及以下数据等role_list request.user.role.filter(status1).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, 24]# 5. 仅访问本人数据考虑到部门可能会变更所以再添加当前部门条件if 0 in data_permissions_list:if not getattr(queryset.model, depart_id, None):return queryset.filter(creatorrequest.user)else:# 换部门了就不能访问原来部门的数据return queryset.filter(creatorrequest.user, depart_iddepart_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(status1).values_list(depart__id, flatTrue))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__inlist(set(depart_list)))else:return queryset# 没用到
class UsersManageFilter(django_filters.rest_framework.FilterSet):用户管理 简单过滤器URL格式http://127.0.0.1:8100/?start_time2022-10-02 08:00:00end_time2023-12-31 23:59:59# 1.创建时间从start_time django_filters.DateTimeFilter(field_namecreate_datetime, lookup_exprgte)# 2.创建时间到end_time django_filters.DateTimeFilter(field_namecreate_datetime, lookup_exprlte)# 3.用户名-模糊搜索username django_filters.CharFilter(field_nameusername, lookup_expricontains)# 4.手机号码-模糊搜索mobile django_filters.CharFilter(field_namemobile, lookup_expricontains)class Meta:model Userfields []def get_depart(depart_id, depart_all_listNone, depart_listNone):递归获取部门的所有下级部门: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在具体的视图集中这样写就实现了