【问题标题】:Flask SQLAlchely UPDATE instead of INSERT烧瓶 SQLAlchemy 更新而不是插入
【发布时间】:2021-07-19 16:55:45
【问题描述】:

我正在关注 Corey Schafer 的教程系列,用于制作 Flask Web 应用程序,但我做错了。因此,当从用户向数据库发布新帖子时,它会使用表单中的数据写入数据库,但是当我尝试从 same 用户添加另一篇帖子时,我收到错误:

[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)

这是添加新帖子的路径:

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

在视频中,他发布了一个新帖子,但来自另一个用户帐户。我怎样才能逃脱呢?

整个错误是这样的:

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

【问题讨论】:

  • 是否 current_user.is_authenticated?
  • 我的意思是用户实际登录了吗?请参阅签入registerlogin 路线。此外,对于您的帖子,您只需要 user_id,所以没有理由传递所有对象,只需传递 current_user.id。
  • 您确定与生成此错误消息的路由相同吗?进行一些调试,在代码中添加一些打印以确保。看起来是 PUT 被称为而不是 POST
  • 你能从控制台给出整个错误信息吗?
  • current_user 在会话中吗? current_user in db.session 显示什么?

标签: python sqlite flask sqlalchemy


【解决方案1】:

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

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

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

【讨论】:

  • 是的,谢谢,这行得通,但authoruser 模型中是反向引用,如here 所示
  • 是的,但是backref 是一个用于获取相关对象的属性,而不是用于设置它
  • 谢谢。这是有用的信息。
  • 不,relationship backref 用于在另一端创建镜像relationship 属性,通常也应该支持分配。 “backref 是用于获取相关对象的属性,而不是设置它”为 false。
  • @IljaEverilä,你是对的,谢谢你的纠正,我更新了我的答案
猜你喜欢
  • 2013-11-22
  • 2012-12-29
  • 2021-04-10
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 2020-01-29
  • 1970-01-01
  • 2022-10-21
相关资源
最近更新 更多