python - 如何使 sqlalchemy session 跟踪本地创建的对象中的所有更改?

标签 python postgresql sqlalchemy commit

如果我这样做,Sqlalchemy 会跟踪所有更改并提交到数据库:

b =  this_session.query(BaseUrl).filter_by(id=value).first()
b.basevalue = "new_value" #changing 
this_session.commit()     #commit the change to the DB

效果很好。

但是,如果我使用这个:

proxy =  this_session.execute("select * from base_url where id = {0}".format(value))
b = create_base_url(proxy) #create an instance of BaseUrl from proxy!
b.basevalue = "new_value"  #changing 
this_session.commit()      #it does NOT commit the change to the DB

当然是create_base_url()的问题。在此函数中,我只是通过传递从 proxy 获取的各种参数来创建 BaseUrl 实例并返回它。为了让 this_session 跟踪对象中的所有更改,我没有做任何其他事情。我需要这样的功能:

this_session.attach(b) #keep track of changes in b

以便跟踪b中的所有更改。

我应该如何实现这样的功能?如果我有相反的也很好:

this_session.detach(b) #don't keep track of changes in b

我正在使用 postgresql 9.2sqlalchemy 0.9.0

除了一些帮助之外,文档的链接(处理此问题的部分)也很棒,这样我就可以详细阅读它。 :-)

最佳答案

看来您需要阅读一些 SQLAlchemy 的 native 文档。它写得很好,可以帮助解决很多问题,尤其是一些基本问题。使用 ORM 时,有两点绝对必读:

在进入 SQLAlchemy 之前,您必须阅读这些内容。

在解决您的问题之前,接下来要做的事情是:

proxy =  this_session.execute("select * from base_url where id = {0}".format(value))

永远,永远,不要这样做!这使你容易受到 SQL 注入(inject)攻击,而你不希望这样,特别是如果你有这样一个强大的 ORM 来为你处理它。有几种方法可以替代它。最简单的方法是使用 Session.execute 中记录的绑定(bind)参数。 :

proxy =  this_session.execute("select * from base_url where id = :value", {"value": value})

您还可以直接使用 SQLAlchemy 核心来创建漂亮的语句。为此,您可能想阅读同样出色的SQL Expression Language Tutorial .

现在讨论您的实际问题:

this_session.add(b)

这就是您想要的attach:对象被添加到 session (和数据库)中。删除是双重的:如果你想从数据库中删除它:

this_session.delete(b)

如果您只想将其与 session 分离:

this_session.expunge(b)

但通常情况下,除非将它们再次添加到新 session 中,否则不会将它们从 session 中删除。对于正常的用例来说,这没有必要知道,但也有很好的文档记录,因此很容易阅读。

关于 SQL 注入(inject)(或者为什么绑定(bind)参数很重要):

我只会简要说明问题,有关更广泛的解释,请自行搜索,因为有大量资源。

问题:想象一下您可以将value设置为任何东西。您还可以将其设置为文字 SQL 语句,例如:

value = "0 UNION SELECT * FROM admin_table"

如果运行它会产生:

"select * from base_url where id = 0 UNION SELECT * FROM admin_table"

我只是在这里举了一个例子,但想象一下这个表包含您的管理凭据。你还有很多事情可以做,但这一切都很糟糕。但现在让我们看看绑定(bind)参数是如何做到这一点的:

"select * from base_url where id = '0 UNION SELECT * FROM admin_table'"

你看,它被引用了。是的,你也可以引用它,但这甚至可以解决这个问题(如果你感兴趣,请阅读,否则就这样做)。

在 session 中添加:

你是对的,如果你创建一个已经存在的对象(为什么要这样做?),那么 SQLAlchemy 将尝试添加它(因为它不知道你创建了现有的对象,它假设你会通过查询来检索它)。因此,如果这确实是您的用例,那么 Session.merge 可能会帮助您,或者您必须处理对象的状态(即使其“非 transient ”)。但在尝试这样做之前,请阅读上面链接的文档,因为我解释的所有内容(以及更多内容)都以更好的方式进行了解释。

关于python - 如何使 sqlalchemy session 跟踪本地创建的对象中的所有更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18633054/

相关文章:

python - 打开张量板时出错

python - 检查是否存在重复,然后在行中附加一个唯一的数字?

sql - 在 postgres 中使用函数时出现语法错误

c# - PostgreSQL 相当于 IF @@ROWCOUNT=0 INSERT INTO

python - 如何提高包含 sqlalchemy 查询语句作为条件的循环的速度

python - 如何以 pythonic 方式顺利集成 SQLAlchemy 和子类 Numpy.ndarray?

python - urllib.request.Request 说参数无效

database - 在具有共享/独占锁的数据库中,当事务开始时执行UPDATE语句时,锁是如何工作的?

python - 获取 sqlalchemy 基类对象而不是子对象

python - 安装Mac后找不到LightGBM镜像