树莓派上基于Flask与MySQL数据库的RESTful API调试问题求助
解决Flask+Marshmallow SQLAlchemy POST请求中的AttributeError问题
我一看你这报错就知道核心问题出在哪了——SQLAlchemySchema默认的load()方法返回的是字典,不是你的Todo模型实例,所以你调用create()方法才会各种报错。咱们一步步来把这个问题搞定:
问题根源拆解
- 第一个错误
AttributeError: 'dict' object has no attribute 'create':你用todo_schema.load(data)拿到的是个字典,而字典肯定没有create()方法啊,这是因为SQLAlchemySchema默认不返回模型实例。 - 第二个错误
TypeError: create() missing 1 required positional argument: 'self':你改成Todo.create()后,又把实例方法当成类方法调用了,create()是需要通过Todo实例来调用的,直接用类调用当然缺self参数。
具体解决方案
1. 修改TodoSchema,让它返回模型实例
在TodoSchema的Meta类里加一行load_instance=True,这样load()方法就会返回Todo的实例,而不是字典:
class TodoSchema(SQLAlchemySchema): class Meta(SQLAlchemySchema.Meta): model = Todo sqla_session = db.session load_instance = True # 关键配置:启用实例加载 id = fields.Number(dump_only=True) title = fields.String(required=True) todo_description = fields.String(required=True)
2. 恢复原有的create()调用逻辑
现在todo_schema.load(data)能拿到Todo实例了,你可以把代码改回最初的写法:
@app.route('/api/v1/todo', methods=['POST']) def create_todo(): data = request.get_json() print(data) todo_schema = TodoSchema() todo = todo_schema.load(data) result = todo_schema.dump(todo.create()) return make_response(jsonify({"todo": result}), 200)
3. 顺便解决启动时的SQLAlchemy警告
在你的app配置里加上这一行,消除那个烦人的SQLALCHEMY_TRACK_MODIFICATIONS警告:
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
4. 适配Flask 2.x+的上下文问题
我还帮你加了应用上下文包裹db.create_all(),避免在新版本Flask里创建表时出现上下文错误:
with app.app_context(): db.create_all()
修改后的完整代码
from flask import Flask, request, jsonify, make_response from flask_sqlalchemy import SQLAlchemy from marshmallow import fields from marshmallow_sqlalchemy import SQLAlchemySchema import json app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:root@localhost:3306/todo' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 消除警告 db = SQLAlchemy(app) # Model class Todo(db.Model): __tablename__ = "todos" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(20)) todo_description = db.Column(db.String(100)) def create(self): db.session.add(self) db.session.commit() return self def __init__(self, title, todo_description): self.title = title self.todo_description = todo_description def __repr__(self): return f"{self.id}" # 用上下文包裹表创建操作 with app.app_context(): db.create_all() class TodoSchema(SQLAlchemySchema): class Meta(SQLAlchemySchema.Meta): model = Todo sqla_session = db.session load_instance = True # 启用实例加载 id = fields.Number(dump_only=True) title = fields.String(required=True) todo_description = fields.String(required=True) @app.route('/api/v1/todo', methods=['POST']) def create_todo(): data = request.get_json() print(data) todo_schema = TodoSchema() todo = todo_schema.load(data) result = todo_schema.dump(todo.create()) return make_response(jsonify({"todo": result}), 200) @app.route('/api/v1/todo', methods=['GET']) def index(): get_todos = Todo.query.all() todo_schema = TodoSchema(many=True) todos = todo_schema.dump(get_todos) return make_response(jsonify({"todos": todos})) @app.route('/api/v1/todo/<id>', methods=['GET']) def get_todo_by_id(id): get_todo = Todo.query.get(id) todo_schema = TodoSchema() todo = todo_schema.dump(get_todo) return make_response(jsonify({"todo": todo}))
最后检查
确保你的树莓派上MariaDB服务在运行,todo数据库已经创建,配置里的用户名和密码也没问题,然后再用Postman发POST请求,应该就能正常创建Todo条目了。
内容的提问来源于stack exchange,提问作者VinRocka
相关产品推荐
相关产品推荐

