清理我的 SQLAlchemy 操作(减少重复)
cleaning up my SQLAlchemy operations (reducing repetition)
我有一些数据的服务器端处理(客户端库= jQuery DataTables
)
我正在使用 POST
作为我的 ajax
方法。在我的 Flask
网络应用程序中,我可以使用 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]
...
所有列名也作为键包含在请求中。具有搜索词的列将搜索字符串作为列名称键的值(而不是对于没有输入搜索词的列为空。因此,如果我想搜索 firstname
包含 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
是空的。所以我下面的代码非常不干
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))
我想知道是否有一种方法可以像上面的排序代码一样简化这组过滤查询,因为我必须对许多其他模型执行此操作。
这应该有帮助:
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()
函数中不包含日期范围过滤,如果您愿意,可以添加此功能,您的代码可以满足此目的。
旁注:注意日期的 bigger/smaller 运算符。您排除了实际要求的日期。使用 <= 或 >= 将日期包含在过滤操作中。这对我来说总是一个陷阱..
我有一些数据的服务器端处理(客户端库= jQuery DataTables
)
我正在使用 POST
作为我的 ajax
方法。在我的 Flask
网络应用程序中,我可以使用 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]
...
所有列名也作为键包含在请求中。具有搜索词的列将搜索字符串作为列名称键的值(而不是对于没有输入搜索词的列为空。因此,如果我想搜索 firstname
包含 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
是空的。所以我下面的代码非常不干
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))
我想知道是否有一种方法可以像上面的排序代码一样简化这组过滤查询,因为我必须对许多其他模型执行此操作。
这应该有帮助:
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()
函数中不包含日期范围过滤,如果您愿意,可以添加此功能,您的代码可以满足此目的。
旁注:注意日期的 bigger/smaller 运算符。您排除了实际要求的日期。使用 <= 或 >= 将日期包含在过滤操作中。这对我来说总是一个陷阱..