Python中PostgreSQL查询返回None,PgAdmin运行正常
问题:调用PostgreSQL查询函数时触发AttributeError错误
问题详情
我编写了Python函数is_paying_user,用于查询PostgreSQL数据库public."Users"表的is_paying字段:
def is_paying_user(user_id: int) -> bool: with Database() as cursor: res = cursor.execute(f"""SELECT is_paying FROM public."Users" WHERE user_id = {user_id}""") return res.fetchone()
自定义的Database上下文管理器定义如下:
class Database: def __init__(self): self.connection = psycopg2.connect(database="postgres", user=DB_USER, password=DB_PASS, host=LOCALHOST, port=DB_PORT) def __enter__(self): return self.connection.cursor() def __exit__(self, exc_type, exc_val, exc_tb): self.connection.commit() self.connection.close()
调用该函数时抛出错误:
AttributeError: 'NoneType' object has no attribute 'fetchone'
使用相同user_id在PgAdmin中执行相同查询可成功,尝试两种参数化查询写法后仍报相同错误:
cursor.execute("""SELECT trackables_amount FROM public."Users" WHERE user_id = %s""", (user_id,)) cursor.execute("""SELECT trackables_amount FROM public."Users" WHERE user_id = %s""", user_id)
解决方法
错误根源
cursor.execute()方法执行SQL后返回值为None,你将这个None赋值给了res,后续调用res.fetchone()自然会触发AttributeError。
修复后的代码
直接使用上下文管理器返回的游标对象调用fetchone(),无需接收execute()的返回值,同时修正参数化查询的正确写法:
def is_paying_user(user_id: int) -> bool: with Database() as cursor: # 正确的参数化查询,避免SQL注入 cursor.execute("""SELECT is_paying FROM public."Users" WHERE user_id = %s""", (user_id,)) result = cursor.fetchone() # 处理用户不存在的情况,返回默认值False return result[0] if result else False
关键注意点
- 参数化查询格式:psycopg2要求参数必须是元组类型,因此第二个参数必须写成
(user_id,)(末尾的逗号不能省略,否则会被识别为单个值而非元组),你之前的第二种写法直接传user_id是错误的。 - 空结果处理:如果查询的
user_id不存在,fetchone()会返回None,必须添加判断逻辑,避免索引访问报错。 - 避免SQL注入:永远不要用字符串格式化拼接SQL语句(如最初的f-string写法),这会引入严重的安全漏洞,必须使用参数化查询。
内容的提问来源于stack exchange,提问作者Eliran Turgeman
相关产品推荐
相关产品推荐

