Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 防止SQLAlchemy在过期对象上重新运行查询的正确方法?_Python_Sqlalchemy_Flask_Flask Sqlalchemy - Fatal编程技术网

Python 防止SQLAlchemy在过期对象上重新运行查询的正确方法?

Python 防止SQLAlchemy在过期对象上重新运行查询的正确方法?,python,sqlalchemy,flask,flask-sqlalchemy,Python,Sqlalchemy,Flask,Flask Sqlalchemy,我在思考如何处理烧瓶请求中过期的sqlalchemy对象时遇到了麻烦。假设我做了如下的事情: from models import Foo, Bar @app.route("/page") def page(): foos = Foo.query.all() for foo in foos: b = Bar(foo.data) db.session.add(b) db.session.commit() return render_template('pag

我在思考如何处理烧瓶请求中过期的sqlalchemy对象时遇到了麻烦。假设我做了如下的事情:

from models import Foo, Bar

@app.route("/page")
def page():
  foos = Foo.query.all()

  for foo in foos:
    b = Bar(foo.data)
    db.session.add(b)

  db.session.commit()

  return render_template('page.html', foos=foos)
然后在page.html中:


SQLAlchemy随后将对模板循环中的每个foo执行select查询,因为session.commit将foos集合标记为过期。如果我知道foos实际上没有改变的方法,那么什么是防止执行lenfoos查询的正确方法?类似地,如果foos已更改,那么使用单个查询而不是多个查询刷新数据的正确方法是什么?

如果您知道foos无法更新,为什么还要发出db.session.commit?如果是有时,那么在其中加入一些逻辑,只有在某些内容已更新时才会触发提交

您可以在db.session.commit行下面添加一个foos=Foo.query.all。然后,只需对所有数据启动一个查询,而不是每行一个查询

正如您所说,提交数据会将其设置为过期,因此需要重新查询它们。也许您可以刷新会话,而不是重新查询更多信息,这些信息似乎表明您可以执行session.refreshobject

更新:使用两个会话 您可以使用第二个会话,您将使用它来查询Foo,然后使用另一个会话来处理条形图。这将使foos在您提交时保持不变,因此您不必再次访问它

下面是一个粗略的例子:

from flask.ext.sqlalchemy import Session

@app.route('/example/')
def home():
    session_two = Session(bind=db.engine.connect())
    foos = session_two.query(Foo).all()

    for foo in foos:
        db.session.add(Bar(foo))
    db.session.commit()

    return render_template_string('''
        {% for foo in foos %}
            {{ foo.name }}
        {% endfor %}
    ''', foos=foos)
另外,我想知道您是否可以使用单个会话来处理它,该会话已配置为expire\u on\u commit=False:

提交的另一个行为是,默认情况下,提交完成后,它将使所有实例的状态过期。这样,当下次通过属性访问或查询结果集中存在的实例访问实例时,它们将收到最新状态。要禁用此行为,请将sessionmaker配置为expire\u on\u commit=False

使用Session.expunge 根据需要从会话中删除对象

@app.route('/')
def home():
    foos = Foo.query.all()
    for foo in foos:
        db.session.add(Bar(foo))
        db.session.expunge(foo)
    db.session.commit()

    return render_template_string('''
        {% for foo in foos %}
            {{ foo.name }}
        {% endfor %}
    ''', foos=foos)

我有一个稍微不同的方法,我不推荐99%的情况。但我还是要和你分享

我对通过SqlAlchemy获取的数据进行快速缓存。为了在live SqlAlchemy对象和缓存数据之间假装级别奇偶性,我执行以下引用

当数据进入缓存时,我将其转换为原始数据,即删除所有sqlalchemy信息。我只想要桌子上的信息

当我从缓存中提取数据时,我会将其转换为ObjectivedAct。这是一个dict,它只提供基于点的属性访问,就像SqlAlchemy对象一样

从缓存中提取数据的例程还可以将属性指定为lazyloaded函数,这是在我从缓存中提取数据时编写的。通过这种方式,我可以将“Useraccount”对象的photo属性关联为从缓存中提取特定照片的函数

使用这种方法,我的只读部分使用与应用程序的可写部分相同的模板——唯一的区别是,如果查看视图,一个部分上的对象是dicts的版本,而其他部分是实际的SqlAlchemy


99%的情况下,我不建议这样做。但是,在您试图持久保存缓存数据的1%情况下,我发现这是最好的解决方案。

对不起,原来的问题不清楚,我已经更新了它。当第一次在foos上循环时,我确实使用了另一个数据库对象,这将导致需要提交的更改。但是,这些更改永远不会导致对foos的更改。看起来有几个选项:1将要再次使用的值复制到非模型中;2在呈现模板后提交;3使用db.session.expunge从会话中分离对象;4按照您的建议,使用2个疗程。似乎每一个都有其适当的用例。谢谢添加了删除示例-仅执行db.session.expungefos似乎不起作用。您必须在行级别上工作。是的,必须在循环中执行。您可以使用“db.session.expunge_all”来分离会话中的所有内容,但在这种情况下没有任何内容可提交。@Doobeh您在第一个链接中引用了sqlalechemy上的0.5分支。您还错过了文档中的这一行:提交的另一个行为是,默认情况下,在提交完成后,它将终止所有实例的状态。这样,当下次通过属性访问或查询结果集中存在的实例访问实例时,它们将收到最新状态。要禁用此行为,请将sessionmaker配置为expire\u on\u commit=false,这当然是个好主意;但我看到了它的吸引力。它认为对于我的用例来说可能有点太多了。我的绝大多数对象永远不会在缓存中。不过我会记住这一点。
@app.route('/')
def home():
    foos = Foo.query.all()
    for foo in foos:
        db.session.add(Bar(foo))
        db.session.expunge(foo)
    db.session.commit()

    return render_template_string('''
        {% for foo in foos %}
            {{ foo.name }}
        {% endfor %}
    ''', foos=foos)