这是我偶然发现的一个奇怪的错误,我不确定它为什么会发生,无论它是 SQLAlchemy 中的错误、Flask-SQLAlchemy 中的错误,还是我还不知道的 Python 的任何特性。
我们使用 Flask 0.11.1,Flask-SQLAlchemy 2.1 使用 PostgreSQL 作为 DBMS。
示例使用以下代码更新数据库中的数据:
entry = Entry.query.get(1)
entry.name = 'New name'
db.session.commit()
这在从 Flask shell 执行时完全正常,因此数据库已正确配置。现在,我们用于更新条目的 Controller 稍微简化了(没有验证和其他样板文件),如下所示:
def details(id):
entry = Entry.query.get(id)
if entry:
if request.method == 'POST':
form = request.form
entry.name = form['name']
db.session.commit()
flash('Updated successfully.')
return render_template('/entry/details.html', entry=entry)
else:
flash('Entry not found.')
return redirect(url_for('entry_list'))
# In the application the URLs are built dynamically, hence why this instead of @app.route
app.add_url_rule('/entry/details/<int:id>', 'entry_details', details, methods=['GET', 'POST'])
当我在 details.html 中提交表单时,我可以看到非常好的更改,这意味着表单已正确提交,有效并且模型对象已更新。然而,当我重新加载页面时,更改消失了,就好像它已被 DBMS 回滚一样。
我启用了 app.config['SQLALCHEMY_ECHO'] = True,我可以在自己手动提交之前看到“ROLLBACK”。
如果我改变行:
entry = Entry.query.get(id)
收件人:
entry = db.session.query(Entry).get(id)
如 https://stackoverflow.com/a/21806294/4454028 中所述,它确实按预期工作,所以我猜测 Flask-SQLAlchemy 的 Model.query 实现中存在某种错误。
然而,由于我更喜欢第一种构造,我对 Flask-SQLAlchemy 做了一个快速修改,并重新定义了原始的 query @property:
class _QueryProperty(object):
def __init__(self, sa):
self.sa = sa
def __get__(self, obj, type):
try:
mapper = orm.class_mapper(type)
if mapper:
return type.query_class(mapper, session=self.sa.session())
except UnmappedClassError:
return None
收件人:
class _QueryProperty(object):
def __init__(self, sa):
self.sa = sa
def __get__(self, obj, type):
return self.sa.session.query(type)
其中sa是Flask-SQLAlchemy对象(即controller中的db)。
现在,这就是事情变得奇怪的地方:它仍然没有保存更改。代码完全一样,但 DBMS 仍在回滚我的更改。
我读到 Flask-SQLAlchemy 可以在拆卸时执行提交,并尝试添加这个:
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
突然之间,一切正常。问题是:为什么?
拆解不是应该只在 View 完成渲染时发生吗?为什么修改后的 Entry.query 的行为与 db.session.query(Entry) 不同,即使代码相同?
最佳答案
以下是对模型实例进行更改并将其提交到数据库的正确方法:
# get an instance of the 'Entry' model
entry = Entry.query.get(1)
# change the attribute of the instance; here the 'name' attribute is changed
entry.name = 'New name'
# now, commit your changes to the database; this will flush all changes
# in the current session to the database
db.session.commit()
注意:不要使用 SQLALCHEMY_COMMIT_ON_TEARDOWN,因为它被认为是有害的并且也已从文档中删除。参见 the changelog for version 2.0 .
编辑:如果您有两个普通 session 对象(使用sessionmaker()创建)而不是scoped session ,然后调用 db.session.add(entry) 上面的代码将引发错误 sqlalchemy.exc.InvalidRequestError: Object '' is already attached to session '2' (this is ' 3')。有关 sqlalchemy session 的更多信息,请阅读以下部分
我们主要从 sessionmaker() 调用构建并用于与我们的数据库通信的 session 对象是一个普通 session 。如果您第二次调用 sessionmaker(),您将获得一个新的 session 对象,其状态独立于之前的 session 。例如,假设我们有两个按以下方式构造的 session 对象:
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
from sqlalchemy import create_engine
engine = create_engine('sqlite:///')
from sqlalchemy.orm import sessionmaker
session = sessionmaker()
session.configure(bind=engine)
Base.metadata.create_all(engine)
# Construct the first session object
s1 = session()
# Construct the second session object
s2 = session()
那么,我们将无法同时向 s1 和 s2 添加相同的 User 对象。换句话说,一个对象最多只能附加一个唯一的 session 对象。
>>> jessica = User(name='Jessica')
>>> s1.add(jessica)
>>> s2.add(jessica)
Traceback (most recent call last):
......
sqlalchemy.exc.InvalidRequestError: Object '' is already attached to session '2' (this is '3')
但是,如果 session 对象是从 scoped_session 对象中检索到的,那么我们就没有这样的问题,因为 scoped_session 对象为同一 session 维护了一个注册表对象。
>>> session_factory = sessionmaker(bind=engine)
>>> session = scoped_session(session_factory)
>>> s1 = session()
>>> s2 = session()
>>> jessica = User(name='Jessica')
>>> s1.add(jessica)
>>> s2.add(jessica)
>>> s1 is s2
True
>>> s1.commit()
>>> s2.query(User).filter(User.name == 'Jessica').one()
请注意 s1 和 s2 是相同的 session 对象,因为它们都是从维护对相同引用的 scoped_session 对象中检索的 session 对象。
因此,尽量避免创建多个正常 session 对象。创建一个 session 对象,并在从声明模型到查询的任何地方使用它。
关于python - Flask-SQLAlchemy db.session.query(Model) 与 Model.query,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40020388/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的
本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决
2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p
ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem
使用rails4,ruby2。我在rails配置中为我的cookiesession设置了30分钟的超时时间。问题是,如果我转到表单,让session超时,然后提交表单,我会收到此ActionController::InvalidAuthenticityToken错误。如何在Rails中优雅地处理这个错误?比如说,重定向到登录屏幕? 最佳答案 在您的ApplicationController:rescue_fromActionController::InvalidAuthenticityTokendoredirect_tosome_p
是否可以在PyYAML或Ruby的Psych引擎中禁用创建anchor和引用(并有效地显式列出冗余数据)?也许我在网上搜索时遗漏了一些东西,但在Psych中似乎没有太多可用的选项,而且我也无法确定PyYAML是否允许这样做.基本原理是我必须序列化一些数据并将其以可读的形式传递给一个不是真正的技术同事进行手动验证。有些数据是多余的,但我需要以最明确的方式列出它们以提高可读性(anchor和引用是提高效率的好概念,但不是人类可读性)。Ruby和Python是我选择的工具,但如果有其他一些相当简单的方法来“展开”YAML文档,它可能就可以了。 最佳答案