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字典里面数据的校验全部用装饰器函数来实现!!!!

.
.
.

posted @   tengyifan  阅读(65)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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
点击右上角即可分享
微信分享提示