从 sqlite3 数据库上的表单提交中的 sqlalchemy 行更新行为不一致

Posted

技术标签:

【中文标题】从 sqlite3 数据库上的表单提交中的 sqlalchemy 行更新行为不一致【英文标题】:Inconsistent behavior with sqlalchemy row update from form submission on sqlite3 database 【发布时间】:2013-10-31 22:30:46 【问题描述】:

目前我的数据库中有一个表,其中包含 id、name (str) 和 data (int) 列。有一个 html 单选按钮表单,其中选择一个按钮会将 1 添加到数据库中的相应条目:

length_table=session.query(func.count(Item.id)).scalar()
randoms=random.sample(range(length_table),2)
item1=session.query(Item).filter_by(id=randoms[0]+1).one()
item2=session.query(Item).filter_by(id=randoms[1]+1).one()

if request.POST.get('myradiobutton') == "left":
    item1.data+=1
    return HTTPFound(location=request.route_url('sorting'))

if request.POST.get('myradiobutton') == "right":
    item2.data+=1
    return HTTPFound(location=request.route_url('sorting'))

这可行,但它有一些伪劣行为(有时会添加到正确的项目,有时会添加到错误的项目)。因为我使用的是pyramid_tm,它应该负责提交。 SQL 日志给了我:

SELECT rowid, *  FROM items ORDER BY rowid; 
SELECT name, sql FROM sqlite_master WHERE type='table' ;
PRAGMA TABLE_INFO(items);
SELECT name, sql FROM sqlite_master WHERE type='index' 

没有对我来说很奇怪的更新语句。如果没有发布,如何更新数据库?我相信更新应该发生在 transaction.commit() 行上。

这是表定义:

class Item(Base):
    __tablename__ = 'items'
    id = Column(Integer, primary_key=True)
    name = Column(Text, unique=True)
    data = Column(Integer)

    def __init__(self, name, data):
        self.name = name
        self.data = data

这是创建引擎的地方:

def main(argv=sys.argv):
    if len(argv) != 2:
        usage(argv)
    config_uri = argv[1]
    setup_logging(config_uri)
    settings = get_appsettings(config_uri)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)

【问题讨论】:

我不明白:您正在通过随机生成的数字进行过滤,并且想知道为什么您的代码具有非确定性行为。但是我对代码的理解还不够深入,无法准确地评论发生了什么。 是的,很奇怪。我试过***.com/questions/19507467/…,但你可以读到我为什么改变它 只需输出您正在运行的查询即可查看您发送到数据库的实际 SQL。然后将该查询与数据库中的数据进行比较。答案很明显 我不太擅长 SQL 语句。我已将 SQL 日志附加到问题中。也许这说明了为什么它不能正常工作? @BigBoy1337:你能试着把这个问题(和未来的问题)分解得更多吗?即使您对 SQL 很陌生,您至少应该能够通过添加一些打印来测试以确保表单为视图函数获取正确的值。如果这不起作用,请修复它。如果该部分确实有效,则使用“拉两条记录并增加其中一条”的代码,并将此逻辑放入其自己的函数中。然后,就该功能提出您的 *** 问题。然后,您(和我们)可以专注于您尝试使用 SQLAlchemy 做什么。 【参考方案1】:

我不完全确定您的 item1item2 来自哪里,但我假设您在发布逻辑之前的某个地方初始化它们,例如:

item1 = DBSession.query(Item).filter(Item.id == passed_value).first()

如果不是,item1item2 是什么?

无论如何,假设您已经有一个有效的 item1 对象并想要更新它,并且您正在使用 ZopeTransactionExtension 我最终会做这样的事情:

if request.POST.get('myradiobutton') == "left":
    item1.data+=1
    DBSession.add(item1)
    DBSession.flush()
    return HTTPFound(location=request.route_url('sorting'))

【讨论】:

在刷新提交更改之前,我应该将项目添加到数据库会话中。但是,您的解决方案似乎无法解决问题。因为我使用的是金字塔框架,所以听说需要使用transaction.commit(),虽然我不完全明白为什么。另外,我已将项目定义添加到问题中,以便您查看它们。 谢谢!我对 Pyramid 也比较陌生,但我认为只有在不使用 ZopeTransactionExtension 时才需要 transaction.commit();我几乎所有内容都基于tutorials from the Pyramid site。在你的模型声明中像 DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) 这样的东西。【参考方案2】:

好的,这就是问题所在。当我第一次调用 item1 和 item2 时,它会使用随机数形式的随机整数随机查询数据库。

但是当它到达item1.data+=1 行时,它会尝试再次随机查询 item1。这意味着无论输出是什么(右或左),它都会再次从数据库中随机选择一个项目来加 1。又名不一致的结果。

为了解决这个问题,我不得不将我的代码分成 GET 和 POST 案例,如下所示。基本上,当页面最初加载时,我在 GET 方法中创建了两个随机“键”。然后我将密钥传递给模板

if request.method == "GET":


        length_table=session.query(func.count(Item.id)).scalar()
        randoms=random.sample(range(1,length_table+1),2)


        results = session.query(Item).filter(Item.id.in_(randoms)).all()


        return 'randoms':randoms,'item1':randoms[0],'item2':randoms[1],'results':results

然后在模板上,我将这些键值放入用户作为隐藏值提交的表单中

<input type="hidden" name="item1" value=$item1>
<input type="hidden" name="item2" value=$item2>

最后,在 POST 部分,我引入了这些值。这意味着它们不会被重新随机化,而是与查询原始项目时使用的键值相同。

if request.method == "POST":

        key1=request.params['item1']
        key2=request.params['item2']
        randoms=[key1,key2]
        results = session.query(Item).filter(Item.id.in_(randoms)).all()
        if output == "left":
            results[0].data=results[0].data+1

            return HTTPFound(location=request.route_url('sorting'))

        if output == "right":
            results[1].data=results[1].data+1
            return HTTPFound(location=request.route_url('sorting'))

【讨论】:

以上是关于从 sqlite3 数据库上的表单提交中的 sqlalchemy 行更新行为不一致的主要内容,如果未能解决你的问题,请参考以下文章

从给定范围中选择行时,sqlite3.OperationalError“SQL 变量太多”

如何从 Jquery 对话框表单提交中调用父页面上的回发?

从表单插入 sql 表时遇到问题 [重复]

PyQt5 - 从 sqlite3 复制到 QTableWidget 的 SQL 行不显示

将表单数据从控制器发送到 AirConsole 上的屏幕

SQLite3删除数据_7