【问题标题】:cleaning up my SQLAlchemy operations (reducing repetition)清理我的 SQLAlchemy 操作(减少重复)
【发布时间】:2015-06-21 22:19:35
【问题描述】:

我对一些数据进行了一些服务器端处理(客户端库 = jQuery DataTables

我使用POST 作为我的ajax 方法。在我的Flask webapp 中,我可以使用request.values 访问POST 数据

request.values的数据类型/结构是werkzeug.datastructures.CombinedMultiDict

如果用户想要对列进行排序,则请求包含一个名为action 的键,其值为filter(注意以下打印输出是使用for v in request.values: print v, request.values[v] 获得的)

...
columns[7][data] role
columns[8][search][regex] false
action filter
columns[10][name] 
columns[3][search][value] 
...

所有列名也作为键包含在请求中。具有搜索词的列将搜索字符串作为列名称键的值(而不是未输入搜索词的列为空。所以,如果我想搜索包含 billfirstname,我会请参阅我的请求中的以下内容

columns[7][searchable] true
...
columns[6][name] 
firstname bill
columns[0][search][value] 
columns[2][searchable] true
...
columns[5][data] phone
role 
columns[10][data] registered_on
...
columns[0][searchable] true
email 
columns[7][orderable] true
...
columns[2][search][value]

注意roleemail 是空的。所以我下面的代码是非常不干的

rv = request.values
if rv.get('action') == 'filter':    
    if len(rv.get('firstname')):
        q = q.filter(User.firstname.ilike('%{0}%'.format(rv.get('firstname'))))
    if len(rv.get('lastname')):
        q = q.filter(User.lastname.ilike('%{0}%'.format(rv.get('lastname'))))
    if len(rv.get('username')):
        q = q.filter(User.username.ilike('%{0}%'.format(rv.get('username'))))
    if len(rv.get('email')):
        q = q.filter(User.email.ilike('%{0}%'.format(rv.get('email'))))
    if len(rv.get('phone')):
        q = q.filter(User.phone.ilike('%{0}%'.format(rv.get('phone'))))
    if len(rv.get('region')):
        q = q.filter(User.region.name.ilike('%{0}%'.format(rv.get('region'))))
    if len(rv.get('role')):
        q = q.filter(User.role.name.ilike('%{0}%'.format(rv.get('role'))))
    if len(rv.get('is_active')):
        q = q.filter(User.is_active_ == '{0}'.format(rv.get('is_active')))
    if len(rv.get('is_confirmed')):
        q = q.filter(User.is_confirmed == '{0}'.format(rv.get('is_confirmed')))
    if len(rv.get('registered_on_from')):
        fdate = datetime.strptime(rv.get('registered_on_from'), '%Y-%m-%d')
        q = q.filter(User.registered_on > fdate)
    if len(rv.get('registered_on_to')):
        tdate = datetime.strptime(rv.get('registered_on_to'), '%Y-%m-%d')
        q = q.filter(User.registered_on < tdate)

我正在构建排序功能,发现以下语句大大简化了我的生活(请参阅this answer

q = q.order_by('{name} {dir}'.format(name=sort_col_name, dir=sort_dir))

想知道是否有办法像上面的排序代码一样简化这组过滤查询,因为我将不得不对许多其他模型执行此操作。

【问题讨论】:

    标签: flask sqlalchemy werkzeug


    【解决方案1】:

    这应该会有所帮助:

    from sqlalchemy import inspect
    from sqlalchemy.sql.sqltypes import String,Boolean
    
    def filter_model_by_request(qry,model,rv):
        if rv.get('action') == 'filter':
            mapper = inspect(model).attrs # model mapper
            col_names = list(set([c.key for c in mapper]) & set(rv.keys()))
            # col_names is a list generated by intersecting the request values and model column names
            for col_name in col_names:
                col = mapper[col_name].columns[0]
                col_type = type(col.type)
                if col_type == String: # filter for String
                    qry = qry.filter(col.ilike('%{0}%'.format(rv.get(col_name))))
                elif col_type == Boolean: # filter for Boolean
                    qry = qry.filter(col == '{0}'.format(rv.get(col_name)))
        return qry
    

    示例调用(我将它与 @app.before_request 和 cURL 调用一起使用以进行验证):

    qry = db.session.query(User)
    print filter_model_by_request(qry,User,request.values).count()
    

    该功能不包含日期范围过滤,如果您愿意,请添加此功能,您的代码可以用于此目的。

    旁注:小心使用较大/较小的日期运算符。您排除了实际请求的日期。使用 = 在过滤操作中包含日期。这对我来说总是一个陷阱..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      • 2017-12-10
      • 2023-03-08
      相关资源
      最近更新 更多