提问人:Mel Boy 提问时间:11/2/2023 最后编辑:Ian WilsonMel Boy 更新时间:11/4/2023 访问量:38
卡在SQLAlchemy从数据库事务问题回滚
Stuck in SQLAlchemy ROLLBACK from database transaction issue
问:
我有一个使用 API 的 Flask 应用程序,并且有一个使用 PSQL 的包含多个表的架构。用户应该能够通过搜索栏进行浏览,也可以单击流派来检索书籍结果并将其显示在 Bootstraps 卡片上。用户应该能够收藏/保存一本书,然后在注册并登录后被带到他们的个人资料页面。我似乎已成功注册、登录,并且对 /users/profile 有一个 GET,但随后我得到了一个回滚,我被送回登录页面。
这是我 app.py 的一部分。我相信我已经导入了所有必要的依赖项。
from flask import Flask, render_template, redirect, flash, session, request, jsonify, url_for
from models import connect_db, db, User, Books
from forms import LoginForm, RegisterForm
from flask_bcrypt import Bcrypt
from flask_login import LoginManager, login_required
app = Flask(__name__, template_folder="templates", static_folder="static")
app.app_context().push()
from flask_login import current_user
from flask_login import login_user, logout_user
bcrypt = Bcrypt()
login_manager = LoginManager()
login_manager.init_app(app)
app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql:///my_books"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_ECHO"] = True
app.config["SECRET_KEY"] = ""
app.config['TESTING'] = True
import requests
API_KEY = ""
migrate = Migrate(app, db)
connect_db(app)
@app.route("/")
def home_page():
""""""
return render_template("index.html")
这是 login_manager.user_loader,我相信我正在正确导入user_id。
@login_manager.user_loader
def user_loader(user_id):
if user_id.isdigit():
user = User.query.get(int(user_id))
return user
return None**
这是我的登录 GET 路由,它显示了登录表单。
@app.route("/users/login", methods=["GET"])
def login_form():
"""Displays the login form."""
form = LoginForm()
return render_template('users/login.html', form=form)
这是我的登录路线,登录后应该将我带到profile.html页面。
from flask import current_app
@app.route("/users/login", methods=["POST"])
def login():
"""Displays login form. Logs in the current user by processing the form"""
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
print("Username from form:", form.username.data)
print("User from the database:", user)
if user:
if login_user(user):
print("Login successful")
flash(f"Hello, {user.username}!", "success")
db.session.commit() # Commit the transaction to the database
return redirect(url_for('profile'))
else:
print("Login failed")
flash("Failed to log in the user.", "danger")
else:
print("User not found")
flash("User not found.", 'danger')
else:
flash("Invalid credentials.", 'danger')
return render_template('users/login.html', form=form)
我做了许多 flash 和 print 语句,我认为由于回滚,这些语句似乎没有出现。
@app.route("/users/logout", methods=["GET"])
def logout():
"""Logout the current user."""
logout_user() # Use Flask-Login logout_user function
return redirect(url_for('home_page'))
@app.route('/users/register', methods=["GET", "POST"])
def handle_registration():
"""Creates a new user and adds user to the DB. Makes sure username & email are unique."""
form = RegisterForm()
if form.validate_on_submit():
# Check if a user with the same username or email already exists
existing_user = User.query.filter((User.username == form.username.data) | (User.email == form.email.data)).first()
if existing_user:
flash("Username or email already taken", 'danger')
return render_template('users/register.html', form=form)
user = User.signup(
first_name=form.first_name.data,
last_name=form.last_name.data,
username=form.username.data,
password=form.password.data,
email=form.email.data,
)
db.session.commit()
flash("Registration successful! Please log in.", 'success')
return redirect(url_for('login_form'))
return render_template('users/register.html', form=form)
from flask_login import current_user
@app.route('/users/profile', methods=["GET"])
def profile():
if current_user.is_anonymous:
flash("You need to log in to see your profile.", 'warning')
return redirect(url_for('login'))
print("Profile route accessed")
# Retrieve the current user's favorite books
favorite_books = current_user.saved_books
return render_template('users/profile.html', favorite_books=favorite_books)
我的 Flask 应用程序加载,我能够浏览、搜索和注册虚假帐户,因此 WTForms 的注册页面正在工作。当我进入登录名并输入我的用户名和密码时,我能够看到我的 HTML 中的登录标签已切换到注销标签,因此这似乎也有效。我还检查了我的架构中的所有数据库是否都显示在 PSQL 中。
这是我 models.py:
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from flask_login import UserMixin
db = SQLAlchemy()
saved_books_association = db.Table(
'saved_books_association',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('book_id', db.Integer, db.ForeignKey('books.id'))
)
这是延续 models.py 的 User 类。我试图关注 Real Python 网站。
class User(db.Model, UserMixin):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
first_name = db.Column(db.String(20), nullable=False)
last_name = db.Column(db.String(20), nullable=False)
email = db.Column(db.String(50), nullable=False)
password = db.Column(db.String(100), nullable=False)
saved_books = db.relationship('Books', secondary=saved_books_association, backref=db.backref('users', lazy='dynamic'))
def __init__(self, first_name, last_name, username, email, password):
self.first_name = first_name
self.last_name = last_name
self.username = username
self.email = email
self.password = bcrypt.generate_password_hash(password).decode('utf-8')
def check_password(self, password):
return bcrypt.check_password_hash(self.password, password)
@classmethod
def signup(cls, first_name, last_name, username, password, email):
"""Sign up a new user and return the user object."""
user = cls(first_name=first_name, last_name=last_name, username=username, password=password, email=email)
db.session.add(user)
return user
def is_active(self):
"""True, as all users are active."""
return True
def get_id(self):
"""Return the user's ID as a string to satisfy Flask-Login's requirements."""
return str(self.id)
def is_anonymous(self):
"""Return True if the user is anonymous, or False if authenticated."""
return not self.is_authenticated()**
我还有其他未包含的数据库模型。这是运行我的 Flask 应用程序时终端中的消息:
127.0.0.1 - - [01/Nov/2023 19:30:09] "POST /users/login HTTP/1.1" 302 -
2023-11-01 19:30:09,361 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-11-01 19:30:09,361 INFO sqlalchemy.engine.Engine SELECT users.id AS users_id, users.username AS users_username, users.first_name AS users_first_name, users.last_name AS users_last_name, users.email AS users_email, users.password AS users_password
FROM users
WHERE users.id = %(pk_1)s
2023-11-01 19:30:09,361 INFO sqlalchemy.engine.Engine [cached since 23.39s ago] {'pk_1': 1}
2023-11-01 19:30:09,362 INFO sqlalchemy.engine.Engine ROLLBACK
127.0.0.1 - - [01/Nov/2023 19:30:09] "GET /users/profile HTTP/1.1" 302 -
2023-11-01 19:30:09,367 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-11-01 19:30:09,367 INFO sqlalchemy.engine.Engine SELECT users.id AS users_id, users.username AS users_username, users.first_name AS users_first_name, users.last_name AS users_last_name, users.email AS users_email, users.password AS users_password
FROM users
WHERE users.id = %(pk_1)s
2023-11-01 19:30:09,367 INFO sqlalchemy.engine.Engine [cached since 23.4s ago] {'pk_1': 1}
2023-11-01 19:30:09,369 INFO sqlalchemy.engine.Engine ROLLBACK
127.0.0.1 - - [01/Nov/2023 19:30:09] "GET /users/login HTTP/1.1" 200 -
我尝试删除我的数据库并重新创建它,更改为使用 UserMixin,并多次重新设计我的 User 类模型,但我仍然停留在回滚上。任何建议都会有很大帮助。
答:
每次使用会话时,都会自动启动事务,然后回滚。所以这可能没有关系。
应该像 ?if current_user.is_anonymous:
if current_user.is_anonymous():
评论
if current_user.is_anonymous:
def is_anonymous.
if current_user.current_user.is_anonymous():
if current_user.is_anonymous:
if current_user.is_anonymous():
@ property
def is_anonymous
上一个:回滚后需要新事务仍影响实体
下一个:Django db 回滚特定提交
评论