flask里面经常用到的一些过滤排序的工具函数代码
.
.
.
查所有接口里面常用的一些功能函数,配合ORM使用
过滤用的一些函数
# db_funcs.py里面的 各种方法
from sqlalchemy import orm, text, or_, and_
# filter是python内置函数名,所以变量名起成了filter1
# 1 全模糊匹配函数
def like_filter(key, value):
return text(" {} like \'%{}%\' ".format(key, value))
# 该函数用法:调用函数传进去的key与value都是字符串
res = like_filter('auth_user.username', 'admin')
print(type(res)) # <class 'sqlalchemy.sql.elements.TextClause'>
# res等于 text(" user.username like '%admin%' ")
# text模块允许你使用原始的SQL语句,并与SQLAlchemy的其他功能集成。
# 正常sql语句要这样写
# select * from user where user.username like '%admin%';
# 使用text模块orm语句要这样写
# res = User.query.filter(text(" user.username like \'%admin%\' "))
# 也就是把原sql语句的where后面的条件,使用字符串的形式,然后用text函数包一下
# 再配合orm语句就能,在最后执行orm语句的时候,转化成和原始一样的sql语句!!!
# \' 转义成 '字符 这个 user.username.like '%admin%' 就是一个原生的sql语句
-----------------------------------------------------------------
-----------------------------------------------------------------
-----------------------------------------------------------------
# 2 全模糊匹配函数
def value_like_filter(key, value):
filter1 = key.like('%{}%'.format(value))
# filter1 = key.like(f'%{value}%')
# print(type(filter1)) <class 'sqlalchemy.sql.elements.BinaryExpression'>
return filter1
# 该方法用的较多
# 该函数的用法,注意调用函数传进去的key与value key不是字符串!!!
key 是 SQLAlchemy 数据模型的某个属性,
value 是用于模糊匹配的搜索值。函数内部使用 like 方法创建了一个模糊匹配的过滤条件 filter1,
这个filter1是一个 <class 'sqlalchemy.sql.elements.BinaryExpression'> 过滤条件
然后返回这个过滤条件。
res = db.session.query(User).filter(User.name.like('%teng%'))
# 这样就写死了,只能用teng来模糊匹配了
res = db.session.query(User).filter(value_like_filter(User.name, 'teng'))
# 这样就写活了,过滤字段与过滤条件都写活了!!!
-----------------------------------------------------------------
-----------------------------------------------------------------
# 3
def equal_filter(key, value):
return text('{} = \'{}\''.format(key, value))
# 4
def value_equal_filter(key, value):
if value is None:
filter1 = (key.is_(None))
else:
filter1 = (key == value)
return filter1
# 5
def bool_filter(key, value):
value = 1 if value else 0
return text('{} = \'{}\''.format(key, value))
# 这3个用的不多
-----------------------------------------------------------------
-----------------------------------------------------------------
# 6 这个函数的作用是将 key(数据模型的某个属性) 与 value_list(字段对应的数据需要在的范围列表)
# 转化成过滤条件的ORM语句
def in_list_filter(key, value_list):
if None not in value_list:
filter1 = (key.in_(value_list))
else:
filter1 = or_(key.in_(value_list), key.is_(None))
return filter1
# 比如:假设前端传的json字典里面{'group_id_list':[1,2,3]}
filters_list = []
if 'group_id_list' in request.json.keys():
filters_list.append(in_list_filter(AuthGroup.id, request.json['group_id_list']))
res = db.session.query(AuthUser).filter(*filters).all()
实际上就是 res = db.session.query(AuthUser).filter(AuthGroup.id in_([1,2,3])).all()
# 这句话的执行结果就是,将AuthGroup.id 属于1,2,3 中任意一个的用户给过滤出来!!!
# 这个需求在,查用户的时候可能会有
-----------------------------------------------------------------
-----------------------------------------------------------------
# 7 调该函数,key传的是字符串
def range_filter(key=None, min_value=None, max_value=None):
if min_value is not None and max_value is not None:
filter_text = f'{key}>={min_value} and {key}<={max_value}'
elif max_value is not None and min_value is None:
filter_text = f'{key}<={max_value}'
elif min_value is not None and max_value is None:
filter_text = f'{key}>={min_value}'
return text(filter_text)
# 最后text括号里面就是一个过滤条件的原生sql字符串 比如 "user.age>=10"
# 该方法用的少,有点多此一举的感觉了,当有多个过滤条件的时候,完全可以这样,不需要调这个函数
# filters_list.append(user.age>=10)
-----------------------------------------------------------------
-----------------------------------------------------------------
# 8
def value_range_filter(key=None, min_value=None, max_value=None, bigger_eq=True, smaller_eq=False):
filter1 = None
if min_value is not None and max_value is not None:
if bigger_eq and not smaller_eq:
filter1 = and_(key < max_value, key >= min_value)
elif not bigger_eq and smaller_eq:
filter1 = and_(key <= max_value, key > min_value)
elif bigger_eq and smaller_eq:
filter1 = and_(key <= max_value, key >= min_value)
else:
filter1 = and_(key < max_value, key > min_value)
elif max_value is not None and min_value is None:
if smaller_eq:
filter1 = and_(key <= max_value)
else:
filter1 = and_(key < max_value)
elif min_value is not None and max_value is None:
if bigger_eq:
filter1 = and_(key >= min_value)
else:
filter1 = and_(key > min_value)
return filter1
# 注释
value_range_filter 函数: 这是一个函数,接受多个参数用于构建范围过滤条件。
主要参数包括 key,min_value,max_value,bigger_eq 和 smaller_eq。它们分别是:
key: SQLAlchemy 模型中的一个属性(列),代表你想要过滤的属性。
min_value 和 max_value: 用于设定范围的最小和最大值。
bigger_eq 和 smaller_eq: 分别表示是否包含大于等于(>=)和 小于等于(<=)关系。
条件判断部分: 这部分根据传入的参数来构建不同的过滤条件,考虑了不同的情况:
如果 min_value 和 max_value 都不为 None,
则根据 bigger_eq 和 smaller_eq 参数的值来创建一个适当的范围过滤条件。
如果只有 max_value 不为 None,则根据 smaller_eq 参数的值来创建一个小于等于的过滤条件。
如果只有 min_value 不为 None,则根据 bigger_eq 参数的值来创建一个大于等于的过滤条件。
return filter1: 返回根据传入参数生成的范围过滤条件。
总之,这个函数可以用于根据不同的情况生成适当的范围过滤条件,
然后你可以将这些条件应用于 SQLAlchemy 查询中,以获取符合指定范围的数据。
# 感觉用的不多,有点鸡肋!!!
# 没必要调这个函数,有这个时间,直接用flask的orm语句直接写该过滤条件了!!!
-----------------------------------------------------------------
-----------------------------------------------------------------
# 9 key 传的不是字符串
def time_range_filter(key=None, min_value=None, max_value=None):
if min_value is not None and max_value is not None:
filter1 = (key < max_value and key >= min_value)
elif max_value is not None and min_value is None:
filter1 = (key < max_value)
elif min_value is not None and max_value is None:
filter1 = (key >= min_value)
else:
pass
return filter1
# 这个方法还有点用,比如当查用户列表,根据用户的创建时间段来过滤的时候,用它还是比较方便的,不要在写orm过滤语句了
# 直接调该函数,传你要过滤的时间最大值或最小值
--------------------------------------------------------
--------------------------------------------------------
.
.
.
.
.
排序配合ORM 常用的函数 重要!!!!
def generate_orderby_text(key_order_set_list: list):
for i, order_set in enumerate(key_order_set_list):
key_order_set_list[i] = '{}{}'.format('-' if order_set['desc'] == True else '', order_set['key'])
return text(','.join(key_order_set_list))
# def generate_orderby_text(key_order_set_list: list):
参数key_order_dict_list 接收一个列表 如这样 [{'key': 'auth_user.id', 'desc': True},]
这个参数应该包含一些包含排序信息的字典,每个字典包含两个键:'key' 和 'desc'。
for i, order_set in enumerate(key_order_set_list):
遍历传入的 key_order_set_list 列表中的每个字典。enumerate 函数返回一个索引和一个字典
key_order_set_list[i] = '{}{}'.format('-' if order_set['desc'] == True else '', order_set['key'])
这一行代码根据字典中的 'desc' 键的值来构建排序文本。
如果 'desc' 的值为 True,则在键名前添加 '-',表示降序排序;
如果 'desc' 的值不为 True,则不添加 '-',表示升序排序。然后将键名添加到排序文本中。
就是将原来的一个列表套字典的结构,遍历出字典后,提取出字典的信息,组合成字符串,
最后再用该字符串,顶掉列表里面,对应位置的原字典
这样循环走完,列表里面的一个个字典,都变成一个个字符串了
return ','.join(key_order_set_list)
循环完成后,将已经构建好的排序文本通过 ','.join() 函数连接起来,用逗号分隔。
最后,这个连接好的排序文本作为函数的返回值。
总之,这个函数用于将一组排序信息(包含键名和排序顺序)转换为排序的文本表示,
以便在查询等操作中使用。排序顺序由 'desc' 键的值来决定,如果为 True,则表示降序排序,否则为升序排序。
可以把上面的代码简化成容易理解一点的代码
def generate_orderby_text(order_list_dict: list):
order_list = []
for i, order_dict in enumerate(order_list_dict):
if order_dict['desc'] == True:
order_list.append(f'-{order_dict["key"]}')
else:
order_list.append(order_dict['key'])
print(order_list) # ['-auth_user.id', 'auth_user.name']
return text(','.join(order_list))
# 调用该函数时,传入的参数为一个列表套字典的类型 [{'key': 'auth_user.id', 'desc': True},]
# 一个字典就代表一个排序规则,当需要两个排序规则的时候,这个列表里就再放一个字典就行了
# 这个函数的目的就是将列表套字典转换为字符串,
# 例如这样 传的字典是 [{'key': 'auth_user.id', 'desc': True},{'key': 'auth_user.name', 'desc': True}]
# 那么最后返回的就是 text('-auth_user.id,auth_user.name')
# text里面是一个大的,用逗号连接的,组合起来的字符串
# text模块允许你使用原始的SQL语句,并与SQLAlchemy的其他功能集成。
# 正常sql语句是这样写的
# select * from auth_user order_by auth_user.id.desc,auth_user.name.asc
# 也可以用正负号代替 select * from auth_user order_by -auth_user.id,+auth_user.name
# 所以用了text之后,配合ORM就可以这样写,通过字符串来实现排序控制!!!
# res = db_session.query(auth_user).order_by(text('-auth_user.id,auth_user.name'))
.
.
.
.
.
.
.
.
.
.
.
.
.
对前端传入数据进行校验,常用的一些装饰器函数
判断前端传的body的数据类型的装饰器函数
# 比如我们可以用来对前端传来的body数据进行校验是不是字典类型
def body_type_is(type):
def _body_type_is(func):
@wraps(func)
def wrapper():
if not isinstance(request.json, type):
return jsonify_operation_msg(False, '未传入正确格式的参数')
return func()
wrapper.__name__ = func.__name__
return wrapper
return _body_type_is
-----------------------------------------------------
# 这个和上面差不多
def body_type_is_dict(func):
def wrapper():
try:
request.json.keys()
except Exception as ex:
return jsonify_return_body(['result', 'code', 'msg'], result=False, msg='未传入key-value格式json')
return func()
wrapper.__name__ = func.__name__
return wrapper
-----------------------------------------------------
# 这个也差不多
def body_type_is(type):
def body_type_is(func):
@wraps(func)
def wrapper():
if not isinstance(request.json, type):
return jsonify_operation_msg(False, '未传入正确格式的参数')
res = func()
return res
wrapper.__name__ = func.__name__
return wrapper
return body_type_is
.
.
.
判断前端传的json字段里面的数据,是否有我们需要的规定字段!!!
def body_need_keys(keys: list):
def _body_need_key(func):
@wraps(func)
def wrapper():
try:
if not isinstance(request.json, dict):
return jsonify_operation_msg(False, '未传入正确格式的参数格式')
not_satisfied_keys = []
except Exception as ex:
return jsonify_operation_msg(False, '请求错误,请检查该请求')
for key in keys:
if isinstance(key, str):
if not request.json.__contains__(key):
not_satisfied_keys.append(key)
if len(not_satisfied_keys) > 0:
return jsonify_operation_msg(False, '未传入\'{}\''.format('\',\''.join(not_satisfied_keys)))
return func()
wrapper.__name__ = func.__name__
return wrapper
return _body_need_key
-----------------------------------------------
# 可以简化成
def body_need_keys(keys: list):
def _body_need_key(func):
@wraps(func)
def wrapper():
try:
if not isinstance(request.json, dict):
return jsonify_operation_msg(False, '未传入正确格式的参数格式')
not_satisfied_keys = []
except Exception as ex:
return jsonify_operation_msg(False, '请求错误,请检查该请求')
for key in keys:
if isinstance(key, str):
if not request.json.__contains__(key):
not_satisfied_keys.append(key)
if len(not_satisfied_keys) > 0:
info_str = "\',\'".join(not_satisfied_keys)
return jsonify_operation_msg(False, f"未传入\'{info_str}\'")
return func()
wrapper.__name__ = func.__name__
return wrapper
return _body_need_key
# 作用就是 在装饰器函数里面,提前定义好列表,列表里面放上需要前端传的数据的键
# 这里我们规定了前端传的body是json格式的字典,假设装饰器函数括号里面放了['name','age']
# 那么只要前端body传的json字典里面没有name与age这两个键,就直接返回错误信息,不会执行视图函数了
-------------------------------------------------------
not_satisfied_keys = []
not_satisfied_keys.append('aaa')
not_satisfied_keys.append('bbb')
info_str = "\',\'".join(not_satisfied_keys)
print(info_str) # 把列表搞成字符串 aaa','bbb
res = f"未传入\'{info_str}\'"
print(res, type(res)) # 未传入 'aaa','bbb' <class 'str'>
\' 是转义字符 就是代表就是实际的单引号字符了 , 而不是用来作为标识字符串首尾结束的作用了
---------------------------------------------------------
.
.
.
.
.
.
.
.
.
判断前端传的json字典数据里面的键对应的值,的数据类型 装饰器函数
# 该装饰器函数需要传入一个列表,例如 [('id',int),('name',str)]
def check_request_json_key_type(key_type_tuple_list):
def check_request_json_key_type(func):
@wraps(func)
def wrapper():
for key_type_tuple in key_type_tuple_list:
# 如果元祖里面的字段,在前端传的json字典里面有对应的键,那就调校验函数
# 校验键对应的值,是否属于对应的类型
if key_type_tuple[0] in request.json.keys():
result = check_type_and_range(key=key_type_tuple[0], value=request.json[key_type_tuple[0]],
type=key_type_tuple[1])
if not result.success:
return jsonify_return_body(['result', 'code', 'msg'], result=False, msg=result.msg)
return func()
wrapper.__name__ = func.__name__
return wrapper
return check_request_json_key_type
--------------------------------------------------------
--------------------------------------------------------
# 该函数作用就是对value进行各种校验!!!!!!!!
# 如果传的是type,那么对value的数据类型进行校验,不符合就返回错误对象
# 如果传的是in_list,那么就是判断value,在不在in_list里面后,不在就返回错误对象
# 如果传的是not_in_list,那么就是判断value,在不在not_in_list里面后,在就返回错误对象
# max_value与min_value也一样就是判断value是不是大于max_value或者 小于min_value,是就返回错误对象
def check_type_and_range(key, value, type=None, max_value=None, min_value=None, in_list=None,
not_in_list=None) -> ResultReturner:
# 判断value的数据类型
if type:
if type is int:
if not isinstance(value, type):
return ResultReturner(False, f'{key}类型不是 int ')
if isinstance(value, bool):
# 做这个的判断是布尔类型也属于int类型,所以确定数据是不是int,要额外再校验下数据是不是布尔类型
return ResultReturner(False, f'{key}类型不是 int ')
if not isinstance(value, type):
return ResultReturner(False, f'{key}类型不是{str(type)}')
# 判断value是否在not_in_list里面
if not_in_list:
if value in not_in_list:
return ResultReturner(False, f'{key}不因在{not_in_list}中')
# 判断value是否在in_list里面
if in_list:
if value not in in_list:
return ResultReturner(False, f'{key}因在{in_list}中')
# 判断value是否在最小值与最大值之间
if max_value and min_value:
if value > max_value:
return ResultReturner(False, f'{key}范围大于了{max_value}')
if value < min_value:
return ResultReturner(False, f'{key}范围小于了{max_value}')
# 只判断value是否大于最大值
if max_value:
if value > max_value:
return ResultReturner(False, f'{key}范围大于了{max_value}')
# 只判断value是否小于最小值
if min_value:
if value < min_value:
return ResultReturner(False, f'{key}范围小于了{max_value}')
return ResultReturner(True, '校验成功')
--------------------------------
class ResultReturner():
def __init__(self, success: bool = True, msg: str = '成功', data=None) -> None:
self.success = success
self.msg = msg
if data is not None:
self.data = data
--------------------------------
.
.
.
.
.
.
.
.
.
.
判断前端传的json字典数据里面的键对应的值,在不在我们需要的范围内,装饰器函数
# 例如装饰器函数里面传入 [('name', 'not_in_list', ['']), ('group_id', 'in_list', [1,2,3,4])
# 就是根据元组里面的第二个参数,来确定到底要对value进行怎么样的校验
# 然后通过调用check_type_and_range函数的时候,传对应的校验参数
# 实现对value进行不同的逻辑校验
def check_request_json_key_range(key_range_tuple_list):
def _check_request_json_key_range(func):
@wraps(func)
def wrapper():
for key_range_tuple in key_range_tuple_list:
# 如果元祖里面的字段,在前端传的json字典里面有对应的键,那就调校验函数
# 校验键对应的值,是否
if key_range_tuple[0] in request.json.keys():
if key_range_tuple[1] == 'in':
result = check_type_and_range(key=key_range_tuple[0],
value=request.json[key_range_tuple[0]],
max_value=key_range_tuple[2][1],
min_value=key_range_tuple[2][0])
elif key_range_tuple[1] == 'bigger':
result = check_type_and_range(key=key_range_tuple[0],
value=request.json[key_range_tuple[0]],
min_value=key_range_tuple[2])
elif key_range_tuple[1] == 'smaller':
result = check_type_and_range(key=key_range_tuple[0],
value=request.json[key_range_tuple[0]],
max_value=key_range_tuple[2])
elif key_range_tuple[1] == 'in_list':
result = check_type_and_range(key=key_range_tuple[0],
value=request.json[key_range_tuple[0]],
in_list=key_range_tuple[2])
elif key_range_tuple[1] == 'not_in_list':
result = check_type_and_range(key=key_range_tuple[0],
value=request.json[key_range_tuple[0]],
not_in_list=key_range_tuple[2])
else:
result = ResultReturner(True)
if not result.success:
return jsonify_return_body(['result', 'code', 'msg'], result=False, msg=result.msg)
return func()
wrapper.__name__ = func.__name__
return wrapper
return _check_request_json_key_range
.
.
.
这些装饰器函数的最大作用
以后我们需要对传的json字典里面的键,或键对应的值进行一些判断
比如要求json字典里面必须要求一些对应的键,或者键对应的值必须要在一定的范围类,等这些要求时
就可以直接,用这些装饰器函数,挂到视图函数上面去
这样视图函数里面,就可以只写和业务相关的代码了,
不用再写对于传来的json字典里面数据的校验逻辑了!!!!
json字典里面数据的校验全部用装饰器函数来实现!!!!
.
.
.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY