sai*_*tam 3 python sqlite sqlalchemy unique flask
通常,您如何在Flask中处理唯一的数据库条目?我的数据库模型中有以下专栏:
bank_address = db.Column(db.String(42), unique=True)
Run Code Online (Sandbox Code Playgroud)
问题是,即使在我无法检查它是否已经存在于数据库中之前,也会收到错误消息:
检查它是否唯一,然后将其写入db:
if request.method == 'POST':
if user.bank_address != request.form['bank_address_field']:
user.bank_address = request.form['bank_address_field']
db.session.add(user)
db.session.commit()
Run Code Online (Sandbox Code Playgroud)
我得到的错误:
sqlalchemy.exc.IntegrityError:(sqlite3.IntegrityError)唯一约束失败:user.bank_address_field [SQL:'UPDATE user SET bank_address_field =?在哪里user.id =?']
您不应该捕获并抑制,IntegrityError因为当其他类型的约束(例如外键约束)失败时,可能会引发它。
如今,有一种更好的方法来处理这个错误。SQLite 和 PostgreSQL 都支持ON CONFLICT DO NOTHING和ON CONFLICT DO UPDATE。以下是他们各自的 SQLAlchemy 文档:
sqlalchemy.dialects.sqlite.Insert.on_conflict_do_nothingsqlalchemy.dialects.postgresql.Insert.on_conflict_do_nothing不要使用session.add(),而是使用insert()SQLAlchemy 方言中的函数。它应该大致如下所示:
# if you are using SQLite
from sqlalchemy.dialects.sqlite import insert
# if you are using PostgreSQL
from sqlalchemy.dialects.postgresql import insert
values = dict() # your values here
stmt = (
insert(User)
.values(**values)
.on_conflict_do_nothing(index_elements=[User.bank_address])
)
db.session.execute(stmt)
Run Code Online (Sandbox Code Playgroud)
您可以执行以下两项操作之一:
使用该字段查询用户:
if User.query.filter(User.bank_address == request.form['bank_address_field']).first():
# error, there already is a user using this bank address
Run Code Online (Sandbox Code Playgroud)
但是,这有很大的问题,请参阅下文。
捕获异常:
from sqlalchemy.exc import IntegrityError
try:
db.session.commit()
except IntegrityError:
db.session.rollback()
# error, there already is a user using this bank address or other
# constraint failed
Run Code Online (Sandbox Code Playgroud)
IntegrityError可以从哪里导入sqlalchemy.exc。一旦引发IntegrityError,无论您是否捕获到该错误,您正在使用的会话都会失效。要继续使用该会话,您需要发出db.session.rollback()。
后者更好,因为它不受比赛条件的影响。想象两个用户试图同时注册相同的银行地址:
User.query.filter().first()退货,None因为还没有人使用该地址。User.query.filter().first()退货,None因为还没有人使用该地址。因此,只需捕获异常即可,因为数据库事务可确保在测试约束以及添加或更新用户之前,数据库首先锁定表。
您也可以将整个表锁定在Flask中,但是Python与数据库的通讯要慢得多。如果站点繁忙,则不希望数据库更新缓慢,最终将导致许多用户等待锁被清除。您希望将锁定保持在最小范围内,并且越短越好,并且越接近锁定的实际数据,就越早可以再次释放锁定。数据库非常擅长于这种锁定,并且(非常自然地)非常接近其数据,因此将锁定保留给数据库,而是依靠异常。
| 归档时间: |
|
| 查看次数: |
1327 次 |
| 最近记录: |