Django中raw原生查询ORDER BY列参数传递无效该如何解决
问题原因
你遇到的问题不是Django的raw()方法不支持传参,而是数据库参数化查询本身就不支持将标识符(列名、表名、关键字等)作为参数绑定。
参数化查询的设计目的是绑定查询值,绑定的时候数据库驱动会自动给传入的参数添加字符串引号、做转义处理,你原来的写法最终执行的SQL实际是
SELECT * FROM data_table ORDER BY '你的列名字符串',相当于按固定字符串常量排序,自然不会生效。
解决方法
- 方案1:白名单校验+字符串拼接(最常用,适合必须用原生SQL的场景)
首先要对传入的排序字段做白名单校验,避免SQL注入风险,再通过Python字符串格式化拼入SQL语句,示例代码如下:
# 先定义允许排序的字段白名单,只能从列表里选,避免SQL注入 ALLOWED_ORDER_FIELDS = ['id', 'create_time', 'title', 'amount'] # 校验排序字段合法性,不合法就用默认排序字段 if order_col_name not in ALLOWED_ORDER_FIELDS: order_col_name = 'id' # 直接把校验后的字段名拼入SQL data_list = Data.objects.raw( f'SELECT * FROM data_table ORDER BY {order_col_name}' )
如果需要支持倒序排序,可以再加参数判断,比如传order_type是asc/desc,同样加白名单校验后拼入即可。
- 方案2:ORM原生排序(适合不需要复杂原生查询的场景)
如果你的原生SQL只是简单查全表,完全可以直接用Django ORM的order_by方法,自动规避SQL注入问题:
data_list = Data.objects.all().order_by(order_col_name)
- 方案3:Python内存排序(仅适合数据量极小的场景)
如果数据量很小,也可以在拿到raw查询结果后用Python代码排序,不过数据量超过千条就不推荐,性能损耗很大:
data_list = sorted(Data.objects.raw('SELECT * FROM data_table'), key=lambda x: getattr(x, order_col_name))
安全提醒
绝对不要直接把未校验的用户输入内容直接拼入SQL语句,必须经过白名单校验,否则会存在严重的SQL注入漏洞。
内容的提问来源于stack exchange,提问作者Shale
相关产品推荐
相关产品推荐

