Flask-SQLAlchemy查询无结果(数据库存在对应数据),修改数据库路径后出现JSON序列化错误
我正在开发第一个结合SQLite数据库的Flask应用,遇到了两个棘手的问题:明明数据库里有对应数据,但SQLAlchemy的查询却返回空列表;修改数据库路径后,又出现了JSON序列化错误。下面是我的详细情况和问题细节:
数据库与数据情况
我的数据库是test_db,里面有一张test_table表,结构如下:
fruit_name TEXT NOT NULLorder_amount INTEGER NOT NULLstore_id INTEGER NOT NULL
表中已经存入了3条记录:
- orange, 100, 5
- apple, 250, 8
- peach, 347, 7
初始代码实现
导入与数据库配置
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test_db.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app)
注:test_db.db和Python文件放在同一目录下
数据库模型类
因为没有手动设置主键,我想用SQLite自带的_rowid_作为主键,所以模型类写成这样:
class testTable(db.Model): _rowid_ = db.Column(db.Integer, primary_key=True) fruit_name = db.Column(db.TEXT) order_amount = db.Column(db.INTEGER) store_id = db.Column(db.INTEGER) def __init__(self, fruit_name, order_amount, store_id): self.fruit_name = fruit_name self.order_amount = order_amount self.store_id = store_id
路由与查询逻辑
我写了一个简单的路由,查询fruit_name为"orange"的记录并返回:
@app.route('/') def home(): query_result = testTable.query.filter(testTable.fruit_name == "orange").all() return query_result if __name__ == '__main__': with app.app_context(): db.create_all() app.run(debug=True)
之前看到资料说Flask-SQLAlchemy会把下划线命名的表转为驼峰式,所以我觉得查询部分是没问题的,但启动后页面只显示[],完全查不到数据。
后续更新:修改数据库路径后的新错误
根据建议修改了SQLALCHEMY_DATABASE_URI的路径后,查询空的问题没解决,反而出现了新的JSON序列化错误,完整报错信息如下:
Traceback (most recent call last): File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\app.py", line 2213, in __call__ return self.wsgi_app(environ, start_response) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\app.py", line 2193, in wsgi_app response = self.handle_exception(e) ^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\app.py", line 2190, in wsgi_app response = self.full_dispatch_request() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\app.py", line 1487, in full_dispatch_request return self.finalize_request(rv) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\app.py", line 1506, in finalize_request response = self.make_response(rv) ^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\app.py", line 1820, in make_response rv = self.json.response(rv) ^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\json\provider.py", line 215, in response f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\json\provider.py", line 180, in dumps return json.dumps(obj, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Lnb2628\AppData\Local\Programs\Python\Python311\Lib\json\__init__.py", line 238, in dumps **kw).encode(obj) ^^^^^^^^^^^ File "C:\Users\Lnb2628\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 202, in encode chunks = list(chunks) ^^^^^^^^^^^^ File "C:\Users\Lnb2628\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 430, in _iterencode yield from _iterencode_list(o, _current_indent_level) File "C:\Users\Lnb2628\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 326, in _iterencode_list yield from chunks File "C:\Users\Lnb2628\AppData\Local\Programs\Python\Python311\Lib\json\encoder.py", line 439, in _iterencode o = _default(o) ^^^^^^^^^^^ File "c:\Users\Lnb2628\OneDrive\Documents\Python Projects\flask_practice\practice_env\Lib\site-packages\flask\json\provider.py", line 120, in _default raise TypeError(f"Object of type {type(o).name} is not JSON serializable") TypeError: Object of type testTable is not JSON serializable
问题排查与解决方案
1. 先解决查询无结果的核心问题
查询返回空列表,大概率是模型类和实际数据库表的映射不匹配导致的,我帮你梳理几个关键点:
- 主键定义问题:SQLite的
_rowid_是隐式列,不需要手动在模型类中定义,手动定义反而可能导致映射异常。建议手动添加一个主键列,比如id = db.Column(db.Integer, primary_key=True)。 - 表名映射歧义:虽然Flask-SQLAlchemy默认会把
testTable转为test_table,但显式指定表名更稳妥,避免自动转换的意外。 - 字段类型规范:SQLAlchemy的字段类型应该用小写开头的写法,比如
db.Text、db.Integer,虽然大小写可能不影响,但规范写法能避免潜在问题。 - 数据库文件确认:确认你的
test_db.db是你手动添加了数据的那个文件——有时候db.create_all()会在当前目录创建一个新的空数据库,如果之前的数据在另一个文件里,自然查不到。
修改后的模型类可以改成这样:
class testTable(db.Model): __tablename__ = 'test_table' # 显式指定表名,消除歧义 id = db.Column(db.Integer, primary_key=True) # 手动定义主键 fruit_name = db.Column(db.Text, nullable=False) order_amount = db.Column(db.Integer, nullable=False) store_id = db.Column(db.Integer, nullable=False) def __repr__(self): return f"<testTable {self.fruit_name}>" # 方便调试时查看对象内容
2. 解决JSON序列化错误
当你直接返回query_result(一个包含testTable对象的列表)时,Flask会尝试把它序列化为JSON,但Python对象默认不能直接转为JSON,所以才出现了序列化错误。这里有几种简单的解决方式:
方式一:直接将对象转为字典返回
修改路由函数,把查询到的每个对象转为字典:
@app.route('/') def home(): query_result = testTable.query.filter(testTable.fruit_name == "orange").all() # 把每个对象的字段转为字典 result_list = [ { 'fruit_name': item.fruit_name, 'order_amount': item.order_amount, 'store_id': item.store_id } for item in query_result ] return result_list
方式二:在模型类中添加序列化方法
在testTable类中添加一个to_dict方法,专门返回对象的字典表示:
class testTable(db.Model): __tablename__ = 'test_table' id = db.Column(db.Integer, primary_key=True) fruit_name = db.Column(db.Text, nullable=False) order_amount = db.Column(db.Integer, nullable=False) store_id = db.Column(db.Integer, nullable=False) def to_dict(self): return { 'id': self.id, 'fruit_name': self.fruit_name, 'order_amount': self.order_amount, 'store_id': self.store_id } def __repr__(self): return f"<testTable {self.fruit_name}>"
然后在路由中调用这个方法:
@app.route('/') def home(): query_result = testTable.query.filter(testTable.fruit_name == "orange").all() return [item.to_dict() for item in query_result]
3. 额外调试建议
可以在路由中添加打印语句,方便排查问题:
@app.route('/') def home(): query = testTable.query.filter(testTable.fruit_name == "orange") print(query.statement) # 打印生成的SQL语句,确认是否正确 query_result = query.all() print(query_result) # 打印查询结果,看是否为空 result_list = [item.to_dict() for item in query_result] return result_list
备注:内容来源于stack exchange,提问作者Lnb2628

