You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django SQL查询中转义%报错:列表索引越界

Django原生SQL查询列表索引越界问题排查

场景还原

在pgAdmin中可正常执行的SQL查询:

SELECT <columns>
FROM <tables>
WHERE 
    date_visited >= '2023-05-26 07:05:00'::timestamp 
    AND date_visited <= '2023-05-26 07:07:00'::timestamp
    AND url LIKE '%/mymodule/api/myurl/%';

为了在Django REST接口中调用该查询,编写了如下代码,运行后出现列表索引越界错误:

with connection.cursor() as cursor:
    cursor.execute('''
        SELECT <columns>
        FROM <tables>
        WHERE 
            date_visited >= '%s'::timestamp 
            AND date_visited <=  '%s'::timestamp
            AND url LIKE '%%%s%%';
        ''', [from_date, to_date, url])

问题根源

问题确实出在'%%%s%%'的写法上:
Django的cursor.execute采用参数化查询,这里的%s是数据库占位符,但你把它和Python的字符串转义%%混在了一起。Python会先解析这个字符串:%%%s%%会被转成%s%(第一个%%转为单个%,中间%s保留,最后%%转为单个%),导致实际传入的参数数量和SQL里的占位符数量不匹配,触发索引越界错误。

正确解决方案

方案1:在参数中拼接通配符

把%直接加到传入的url参数前后,SQL里只用%s作为占位符(注意去掉占位符的单引号,参数化查询会自动处理字符串引号):

# 给url前后加上通配符
target_url = f'%{url}%'
with connection.cursor() as cursor:
    cursor.execute('''
        SELECT <columns>
        FROM <tables>
        WHERE 
            date_visited >= %s::timestamp 
            AND date_visited <= %s::timestamp
            AND url LIKE %s;
        ''', [from_date, to_date, target_url])

方案2:用PostgreSQL字符串连接符拼接通配符

如果想在SQL里写通配符,用PostgreSQL的||连接符把%和占位符拼接,避免Python转义冲突:

with connection.cursor() as cursor:
    cursor.execute('''
        SELECT <columns>
        FROM <tables>
        WHERE 
            date_visited >= %s::timestamp 
            AND date_visited <= %s::timestamp
            AND url LIKE '%' || %s || '%';
        ''', [from_date, to_date, url])

额外提示

  • 不要混用Python字符串格式化和数据库参数化占位符,既容易出错,还会带来SQL注入风险。
  • 如果from_date和to_date是Python的datetime对象,可以直接传入,不需要手动转成字符串加::timestamp,PostgreSQL会自动处理类型转换。

内容的提问来源于stack exchange,提问作者MsA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:33:00