Sqlalchemy:InvalidRequestError:Object&#39; <user at =“”0x3a970d0 =“”>&#39;已经附加到会话&#39; 2&#39; (这是&#39; 3&#39;)

时间:2016-02-12 18:27:44

标签: 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)

作为注册过程的一部分,我收到来自表单的电子邮件并处理它从中创建令牌并创建用户,然后使用以下方式向电子邮件发送确认电子邮件:

@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

其中包含嵌入的电子邮件&#39; cluemarine5@mailinator.com'在令牌中。

确认您点击激活以下路线的链接:

@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()

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

1 个答案:

答案 0 :(得分:0)

我终于意识到这个cookiecutter正在使用一个名为'CRUDMixin'的类来进行db操作,它位于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()

它开始工作