清理我的SQLAlchemy操作(减少重复)

时间:2015-04-15 19:20:57

标签: flask sqlalchemy werkzeug

我有一些服务器端处理某些数据(客户端库= jQuery DataTables

我使用POST作为ajax方法。在我的Flask网络应用中,我可以使用POST

访问request.values数据

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] 
...

所有列名称也作为键包含在请求中。具有搜索字词的列将搜索字符串作为列名称键的值(而对于未输入搜索字词的列则为空。因此,如果我要搜索包含firstname的{​​{1}}我会在我的请求中看到以下内容

bill

请注意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] role是如何为空。所以我的代码非常非干

email

我正在构建排序功能,我发现以下声明大大简化了我的生活(参见this answer

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)

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

1 个答案:

答案 0 :(得分: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()

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

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