python - Sqlalchemy : InvalidRequestError: Object '<User at 0x3a970d0>' is already attached to session '2' (this is '3' )

标签 python flask sqlalchemy flask-sqlalchemy

enter image description here

我正在修改 cookiecutter flask 应用程序。我正在尝试关注 https://realpython.com/blog/python/handling-email-confirmation-in-flask/添加电子邮件授权。

我的用户模型在屏幕截图中,也是:

class User(UserMixin, SurrogatePK, Model):

    __tablename__ = 'users'
    username = Column(db.String(80), nullable=True)
    email = Column(db.String(80), nullable=False)
    #: The hashed password
    password = Column(db.String(128), nullable=True)
    created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow)
    first_name = Column(db.String(30), nullable=True)
    last_name = Column(db.String(30), nullable=True)
    active = Column(db.Boolean(), default=False)
    admin = Column(db.Boolean(), default=False)
    confirmed = db.Column(db.Boolean, default=False)
    confirmed_on = db.Column(db.DateTime, nullable=True)


    def __init__(self, username=username, email=email, password=None, **kwargs):
        db.Model.__init__(self, username=username, email=email, **kwargs)
        if password:
            self.set_password(password)
        else:
            self.password = None

    def set_password(self, password):
        self.password = bcrypt.generate_password_hash(password)

作为注册过程的一部分,我收到来自表单的电子邮件并处理它,从中创建 token 并创建 User ,然后使用以下方式向电子邮件发送确认电子邮件:
@blueprint.route("/get_email/", methods=['GET', 'POST'])
def get_email():
    form = EmailForm(request.form, csrf_enabled=False)
    if form.validate_on_submit():
        new_user = User.create(username=None,email=form.email.data)
        token = generate_confirmation_token(form.email.data)
        confirm_url = url_for('user.confirm_email', token=token, _external=True)
        html = render_template('users/activate.html', confirm_url=confirm_url)
        subject = "Please confirm your email"
        send_email(form.email.data, subject, html)
        return redirect(url_for("main.home"))

在这种情况下,我发送了一封电子邮件至:
cluemarine5@mailinator.com

该电子邮件包含一个确认链接,如下所示:
http://127.0.0.1:5000/users/confirm/ImNsdWVtYXJpbmU1QG1haWxpbmF0b3IuY29tIg.CZ-urA.n5IErF0CPPG6EnIwJeSP6mPmDb4

其中包含嵌入的电子邮件“cluemarine5@mailinator.com”在 token 中。

要确认您单击激活以下路线的链接:
@blueprint.route('/confirm/<token>')
def confirm_email(token):
    try:
        email = confirm_token(token)
    except:
        flash('The confirmation link is invalid or has expired.', 'danger')
    user = User.query.filter_by(email=email).first_or_404()
    if user.confirmed:
        flash('Account already confirmed. Please login.', 'success')
    else:
        user.confirmed = True
        user.confirmed_on = datetime.datetime.now()
        db.session.add(user)
        db.session.commit()
        flash('You have confirmed your account. Thanks!', 'success')
    return redirect(url_for('main.home'))

在调试代码工作正常,直到
db.session.commit()

然后我得到上面的错误。我究竟做错了什么?

最佳答案

我终于意识到这个 cookiecutter 正在使用一个名为 'CRUDMixin' 的类来进行数据库操作,它位于 database.py 中:

class CRUDMixin(object):
    """Mixin that adds convenience methods for CRUD (create, read, update, delete)
    operations.
    """

    @classmethod
    def create(cls, **kwargs):
        """Create a new record and save it the database."""
        instance = cls(**kwargs)
        return instance.save()

    def update(self, commit=True, **kwargs):
        """Update specific fields of a record."""
        for attr, value in kwargs.iteritems():
            setattr(self, attr, value)
        return commit and self.save() or self

    def save(self, commit=True):
        """Save the record."""
        db.session.add(self)
        if commit:
            db.session.commit()
        return self

    def delete(self, commit=True):
        """Remove the record from the database."""
        db.session.delete(self)
        return commit and db.session.commit()

class Model(CRUDMixin, db.Model):
    """Base model class that includes CRUD convenience methods."""
    __abstract__ = True

然后我改变了:
db.session.add(user)
db.session.commit()

到:
use.save()

它开始工作

关于python - Sqlalchemy : InvalidRequestError: Object '<User at 0x3a970d0>' is already attached to session '2' (this is '3' ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35369711/

相关文章:

python - Python中按近似比例分配元素

android - 在运行 Flask 服务的 GCP App Engine 服务上接收图像时出现问题

python - 映射属性的基础查询

python - 如何使用python获取json数据的值

python - .loc 与 pandas 一次相同的列

Python:在文本框中使用鼠标滚轮滚动,而鼠标光标不在文本框中(tkinter)

python - websocket 页面在超时后按下提交按钮时重置

python - 使用 WTForms-Alchemy 进行 CSRF 保护

Sqlalchemy 混合体

python - SQLAlchemy 验证 SSL 连接