我正在使用Flask和SQLAlchemy构建一个简单的数据库驱动博客。在博客帖子的模型中,我定义了title和slug属性:
class BlogPost(Model):
...
title = Column(String(80))
slug = Column(String(80), unique=True)
稍后我使用事件监听器自动创建并插入标题中的slug:
@event.listens_for(BlogPost.title, 'set')
def autoslug(target, value, oldvalue, initiator):
target.slug = slugify(value)
正如预期的那样,如果我尝试向数据库添加帖子,并且帖子的标题评估为与之前帖子相同的slug,则事务将因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
答案 0 :(得分:1)
SQLAlchemy在设置时不会将flush更改为将对象建模到数据库。为了得到错误,您必须执行类似
的操作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实现该想法,那么您将失去运气。