我正在使用Flask和SQLAlchemy构建一个简单的数据库驱动博客。在博客发布的模型中,我定义了title和slug属性:
class BlogPost(Model):
...
title = Column(String(80))
slug = Column(String(80), unique=True)
稍后,我使用事件侦听器自动创建标题并从标题中插入一个标签:
@event.listens_for(BlogPost.title, 'set')
def autoslug(target, value, oldvalue, initiator):
target.slug = slugify(value)
不出所料,如果我尝试将一个帖子添加到数据库中,并且该帖子的标题与上一个帖子的评估结果相同,则事务将失败,并出现IntegrityError。我认为实际上无论如何这都不是问题。但是,只是为了咯咯地笑,我尝试了以下方法:
from sqlalchemy.exc import IntegrityError
@event.listens_for(BlogPost.title, 'set')
def autoslug(target, value, oldvalue, initiator):
try:
target.slug = slugify(value)
except IntegrityError:
target.slug = slugify(value) + random_string()
random_string
可以是任何东西,实际上,关键是我尝试执行的任何事情都没有执行,因为没有捕获IntegrityError,而且我不确定为什么-尝试向具有相同标题的数据库中添加并提交帖子当我尝试提交时,仍然会引发IntegrityError并中止事务。我已经看过其他一些关于它的文章,但是答案大多是针对金字塔的,我没有使用。有人知道我在这里想念的吗?
涉及的技术:Python3,Flask,Flask-Sqlalchemy,Sqlalchemy
最佳答案
设置时,SQLAlchemy不会将flush更改为将模型对象更改为DB。为了得到错误,你必须做类似的事情
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm.session import object_session
@event.listens_for(BlogPost.title, 'set')
def autoslug(target, value, oldvalue, initiator):
session = object_session(target)
try:
with session.begin_nested():
target.slug = slugify(value)
session.flush()
except IntegrityError:
target.slug = slugify(value) + random_string()
请注意,您必须将可能的完整性违规包装在嵌套事务(savepoint)中,否则即使捕获
IntegrityError
,整个事务也会失败。如果您的数据库不支持该想法的保存点或SQLAlchemy实现,那么您就不走运了。
关于python - SQLAlchemy事件监听器未捕获IntegrityError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36005090/