Flask教程报错求助:登录后触发AttributeError: 'NoneType'无execute属性
Flask登录后触发AttributeError: 'NoneType' object has no attribute 'execute' 排查方案
我在学习Flask基础博客应用开发,完成Blog Blueprint部分后,登录应用时出现AttributeError: 'NoneType' object has no attribute 'execute',错误指向blog.py第14行的db.execute语句。反复检查代码没找到问题,附上blog.py和auth.py代码,求排查建议或解决方案。
# blog.py代码 from flask import ( Blueprint, flash, g, redirect, render_template, request, url_for ) from werkzeug.exceptions import abort from flaskr.auth import login_required from flaskr.db import get_db bp = Blueprint('blog', __name__) @bp.route('/') def index(): db = get_db() posts = db.execute( 'SELECT p.id, title, body, created, author_id, username' ' FROM post p JOIN user u ON p.author_id = u.id' ' ORDER BY created DESC' ).fetchall() return render_template('blog/index.html', posts=posts) @bp.route('/create', methods=('GET', 'POST')) @login_required def create(): if request.method == 'POST': title = request.form['title'] body = request.form['body'] error = None if not title: error = 'Title is required' if error is not None: flash(error) else: db = get_db() db.execute( 'INSERT INTO post (title, body, author_id)' ' VALUES (?, ?, ?)', (title, body, g.user['id']) ) db.commit() return redirect(url_for('blog.index')) return render_template('blog/create.html') def get_post(id, check_author=True): post = get_db().execute( 'SELECT p.id, title, body, created, author_id, username' ' FROM post p JOIN user u ON p.author_id = u.id' ' WHERE p.id = ?', (id,) ).fetchone() if post is None: abort(404, f"Post id {id} doesn't exist.") if check_author and post['author_id'] != g.user['id']: abort(403) return post @bp.route('/<int:id>/update', methods=('GET', 'POST')) @login_required def update(id): post = get_post(id) if request.method == 'POST': title = request.form['title'] body = request.form['body'] error = None if not title: error = 'Title is required.' if error is not None: flash(error) else: db = get_db() db.execute( 'UPDATE post SET title = ?, body = ?' ' WHERE id = ?', (title, body, id) ) db.commit() return redirect(url_for('blog.index')) return render_template('blog/update.html', post=post) @bp.route('/<int:id>/delete', methods=('POST',)) @login_required def delete(id): get_post(id) db = get_db() db.execute('DELETE FROM post WHERE id = ?', (id,)) db.commit() return redirect(url_for('blog.index'))
# auth.py代码 import functools from flask import ( Blueprint, flash, g, redirect, render_template, request, session, url_for ) from werkzeug.security import check_password_hash, generate_password_hash from flaskr.db import get_db bp = Blueprint('auth', __name__, url_prefix='/auth') @bp.route('/register', methods=('GET', 'POST')) def register(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] db = get_db() error = None if not username: error = 'Username is required.' elif not password: error = 'Password is required.' if error is None: try: db.execute( 'INSERT INTO user (username, password) VALUES (?, ?)', (username, generate_password_hash(password)), ) db.commit() except db.IntegrityError: error = f'Usser {username} is already registered.' else: return redirect(url_for('auth.login')) flash(error) return render_template('auth/register.html') @bp.route('/login', methods=('GET', 'POST')) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] db = get_db() error = None user = db.execute( 'SELECT * FROM user WHERE username = ?', (username,) ).fetchone() if user is None: error = 'Incorrect username.' elif not check_password_hash(user['password'], password): error = 'Incorrect password.' if error is None: session.clear() session['user_id'] = user['id'] return redirect(url_for('index')) flash(error) return render_template('auth/login.html') @bp.before_app_request def load_logged_in_user(): user_id = session.get('user_id') if user_id is None: g.user = None else: g.user = get_db().execute( 'SELECT * FROM user WHERE id = ?', (user_id,) ).fetchone() @bp.route('/logout') def logout(): session.clear() return redirect(url_for('index')) def login_required(view): @functools.wraps(view) def wrapped_view(**kwargs): if g.user is None: return redirect(url_for('auth.login')) return view(**kwargs) return wrapped_view
排查思路与解决方案
这个错误的核心是get_db()返回了None,导致调用db.execute时触发属性错误。以下是具体排查方向:
检查
db.py中get_db()的实现
这是最可能出问题的地方,标准实现应该如下,确保没有遗漏逻辑:import sqlite3 from flask import g def get_db(): if 'db' not in g: g.db = sqlite3.connect( 'flaskr.sqlite', detect_types=sqlite3.PARSE_DECLTYPES ) g.db.row_factory = sqlite3.Row return g.db def close_db(e=None): db = g.pop('db', None) if db is not None: db.close()同时要确认在
app.py中注册了数据库关闭的钩子:from flaskr.db import close_db app.teardown_appcontext(close_db)验证数据库初始化状态
- 检查项目根目录下是否存在
flaskr.sqlite文件,若没有则运行初始化命令:flask --app flaskr init-db - 确认
init-db脚本正确创建了user和post两张表。
- 检查项目根目录下是否存在
调试请求上下文的数据库连接
在auth.py的load_logged_in_user函数中添加调试打印,确认登录后get_db()的返回值:@bp.before_app_request def load_logged_in_user(): user_id = session.get('user_id') db = get_db() print(f"DB connection status: {db}") # 查看是否为None if user_id is None: g.user = None else: g.user = db.execute( 'SELECT * FROM user WHERE id = ?', (user_id,) ).fetchone()运行应用后观察控制台输出,若
db为None,则说明get_db()的逻辑存在问题。检查蓝图注册顺序
在app.py中确保先注册auth蓝图,再注册blog蓝图:from flaskr.auth import bp as auth_bp from flaskr.blog import bp as blog_bp app.register_blueprint(auth_bp) app.register_blueprint(blog_bp)
快速修复步骤
- 确保
db.py的代码与官方教程完全一致,无拼写或逻辑错误。 - 重新运行
flask --app flaskr init-db初始化数据库。 - 重启Flask应用,使用隐身模式测试登录流程。
内容的提问来源于stack exchange,提问作者ridgfam
相关产品推荐
相关产品推荐

