Flask SQLAlchemy 更新而不是插入

Flask SQLAlchely UPDATE instead of INSERT

我正在学习 Corey Schafer 制作 Flask Web 应用程序的教程系列,但我做错了。因此,当涉及到从用户向数据库创建新的 post 时,它会使用表单中的数据写入数据库,但是当我尝试从 添加另一个 post 时相同 用户我收到错误:

[SQL: UPDATE post SET user_id=? WHERE post.id = ?]
[parameters: (None, 1)]

我的 models.py 中有这个不应该让 user_id 成为 None:

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

登录路径:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user and bcrypt.check_password_hash(user.password, form.password.data):
            login_user(user, remember=form.remember.data)
            flash(f'Success.', category='success')
            next_page = request.args.get('next')
            return redirect(next_page) if next_page else redirect(url_for('home'))
        else:
            flash('Unsuccessful!', category='danger')
    return render_template('login.html', title='Log In', form=form)

这是新增路线 post:

@app.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_product():
    form = PostForm()
    if form.validate_on_submit():
        post = Post(name=form.name.data, content=form.content.data, author=current_user)
        db.session.add(post)
        db.session.commit()
        flash('Created!', category='success')
        return redirect(url_for('home'))
    return render_template('new.html', title='Add Post', form=form, legend='New Post')

这是表格:

class PostForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired()])
    content = StringField('Content', validators=[DataRequired()])

在视频中,他制作了一个新的 post,但来自另一个用户帐户。我该如何逃脱?

整个错误是这样的:

127.0.0.1 - - [26/Apr/2021 15:00:34] "POST /post/new HTTP/1.1" 500 -
Traceback (most recent call last):
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1705, in _execute_context
    self.dialect.do_execute(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\default.py", line 716, in do_execute
    cursor.execute(statement, parameters)
sqlite3.IntegrityError: NOT NULL constraint failed: post.user_id

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 2464, in __call__
    return self.wsgi_app(environ, start_response)
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 2450, in wsgi_app
    response = self.handle_exception(e)
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 1867, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "D:\Python\HTML\venv\Lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "D:\Python\HTML\venv\Lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "D:\Python\HTML\venv\Lib\site-packages\flask\app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "D:\Python\HTML\blog\Lib\site-packages\flask_login\utils.py", line 272, in decorated_view
    return func(*args, **kwargs)
  File "D:\Python\HTML\store\routes.py", line 101, in new_product
    db.session.commit()
  File "<string>", line 2, in commit

  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 1423, in commit
    self._transaction.commit(_to_root=self.future)
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 829, in commit
    self._prepare_impl()
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 808, in _prepare_impl
    self.session.flush()
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 3255, in flush
    self._flush(objects)
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 3395, in _flush
    transaction.rollback(_capture_exception=True)
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 70, in __exit__
    compat.raise_(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\util\compat.py", line 211, in raise_
    raise exception
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\session.py", line 3355, in _flush
    flush_context.execute()
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\unitofwork.py", line 453, in execute
    rec.execute(self)
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\unitofwork.py", line 627, in execute
    util.preloaded.orm_persistence.save_obj(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\persistence.py", line 234, in save_obj
    _emit_update_statements(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\orm\persistence.py", line 998, in _emit_update_statements
    c = connection._execute_20(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1520, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\sql\elements.py", line 313, in _execute_on_connection
    return connection._execute_clauseelement(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1389, in _execute_clauseelement
    ret = self._execute_context(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1748, in _execute_context
    self._handle_dbapi_exception(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1929, in _handle_dbapi_exception
    util.raise_(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\util\compat.py", line 211, in raise_
    raise exception
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 1705, in _execute_context
    self.dialect.do_execute(
  File "D:\Python\HTML\venv\Lib\site-packages\sqlalchemy\engine\default.py", line 716, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: post.user_id
[SQL: UPDATE post SET user_id=? WHERE post.id = ?]
[parameters: (None, 1)]
(Background on this error at: http://sqlalche.me/e/14/gkpj)
127.0.0.1 - - [26/Apr/2021 15:00:34] "GET /product/new?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
127.0.0.1 - - [26/Apr/2021 15:00:34] "GET /product/new?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
127.0.0.1 - - [26/Apr/2021 15:00:34] "GET /product/new?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
127.0.0.1 - - [26/Apr/2021 15:00:35] "GET /product/new?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
127.0.0.1 - - [26/Apr/2021 15:00:35] "GET /product/new?__debugger__=yes&cmd=resource&f=ubuntu.ttf HTTP/1.1" 200 -
127.0.0.1 - - [26/Apr/2021 15:00:35] "GET /product/new?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -

解决方案:我在 forms.py 中弄乱了导入,就像这样:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField, TextAreaField
from flask_wtf.file import FileField, FileAllowed
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from store.models import User
from flask_login import current_user

必须重制为:

from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed
from flask_login import current_user
from wtforms import StringField, PasswordField, SubmitField, BooleanField, TextAreaField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from store.models import User

更新:感谢@IljaEverilä,我错了,backref 可以用于分配,而不仅仅是用于检索。我的回答解决了作者的问题,但我对教程代码错误的评论是不正确的,实际问题在另一个地方。有关 backref 的更多信息(带有赋值示例 - SQLAlchemy docs

我把它放在那里是因为看起来提到的教程中的代码有错误。

问题是您没有通过任何 user_id,但您通过了 author。我检查了本教程中的代码,发现 author 字段存在于 Django 模型中,而不是 Flask 中。所以只需将 author=current_user 替换为 user_id=current_user.id 就可以了