【问题标题】:Update a PostgreSQL array using SQLAlchemy使用 SQLAlchemy 更新 PostgreSQL 数组
【发布时间】:2012-12-22 14:07:40
【问题描述】:

我正在尝试使用 SQLAlchemy Core 中的 SQL 语句更新 PostgreSQL 表上的整数数组。我第一次尝试使用查询生成器,但也不知道该怎么做。我相信我使用的方言 Psycopg2 可以自动将数组形成 PostgreSQL 可以接受的格式。

这是表架构:

CREATE TABLE surveys (
    survey_id serial PRIMARY KEY,
    question_ids_ordered INTEGER[],
    created_at TIMESTAMP NOT NULL DEFAULT now(),
);

还有 SQLAlchemy 语句:

survey_id = 46
question_ids_ordered = [237, 238, 239, 240, 241, 242, 243]

with engine.begin() as conn:
    conn.execute("""UPDATE surveys
                    SET question_ids_ordered = %s
                    WHERE survey_id = %s""",
                    question_ids_ordered, survey_id)

我收到的回溯是:

Traceback (most recent call last):
  File "foo.py", line 16, in <module>
    res = add_question_to_group(current_user, 46, 358, question_ids_ordered, new_group_name="Jellyfish?")
  File "/vagrant/workspace/panel/panel/survey.py", line 80, in add_question_to_group
    question_ids_ordered, survey_id)
  File "/home/vagrant/.virtualenvs/project/lib/python2.6/site-packages/sqlalchemy/engine/base.py", line 664, in execute
    params)
  File "/home/vagrant/.virtualenvs/project/lib/python2.6/site-packages/sqlalchemy/engine/base.py", line 808, in _execute_text
    statement, parameters
  File "/home/vagrant/.virtualenvs/project/lib/python2.6/site-packages/sqlalchemy/engine/base.py", line 831, in _execute_context
    None, None)
  File "/home/vagrant/.virtualenvs/project/lib/python2.6/site-packages/sqlalchemy/engine/base.py", line 827, in _execute_context
    context = constructor(dialect, self, conn, *args)
  File "/home/vagrant/.virtualenvs/project/lib/python2.6/site-packages/sqlalchemy/engine/default.py", line 513, in _init_statement
    for p in parameters]
sqlalchemy.exc.StatementError: 'int' object is not iterable (original cause: TypeError: 'int' object is not iterable) 'UPDATE surveys\n                        SET question_ids_ordered = %s\n                        WHERE survey_id = %s' ([237, 238, 239, 240, 241, 242, 243], 46)

我做错了什么?

【问题讨论】:

  • 如果您使用原始 SQL,为什么不完全放弃 ORM?请阅读docs
  • 在这个例子中我没有使用 ORM。我也没有在我的应用程序的任何地方使用 ORM;我使用的是 SQLAlchemy Core,而不是 ORM。
  • ORM 是 SQLAlchemy 中最好的部分,因为它为您提供了可移植性和可重用查询(使用字符串连接构建原始 SQL 很糟糕)。出于好奇,SQLAlchemy Core 为您提供了 Psycopg2 没有提供的哪些功能?
  • 我用多个 VALUES 子句做了很多 INSERT。手工操作意味着大量冗余代码(或我不特别喜欢的一次性功能)。 SQLAlchemy 使这些类型的插入变得容易,此外还使用了一个连接池,这很方便。

标签: python postgresql sqlalchemy


【解决方案1】:

如果你的表是这样定义的:

from datetime import datetime
from sqlalchemy import *
from sqlalchemy.dialects.postgresql import ARRAY

meta = MetaData()
surveys_table = Table('surveys', meta,
    Column('surveys_id', Integer, primary_key=True),
    Column('questions_ids_ordered', ARRAY(Integer)),
    Column('created_at', DateTime, nullable=False, default=datetime.utcnow)
)

然后您可以通过以下方式简单地更新您的数组(与 psycopg2 一起使用):

engine = create_engine('postgresql://localhost')
conn = engine.connect()
u = surveys_table.update().where(surveys_table.c.id == 46).\
     values(questions_ids_ordered=[237, 238, 239, 240, 241, 242, 243])
conn.execute(u)
conn.close()

或者,如果您愿意,可以使用 text() 构造编写原始 SQL:

from sqlalchemy.sql import text
with engine.connect() as conn:
    u = text('UPDATE surveys SET questions_ids_ordered = :q WHERE id = :id')
    conn.execute(u, q=[237, 238, 239, 240, 241, 242, 243], id=46)

【讨论】:

  • 感谢您的回答。你能帮忙用 SQL 做这件事吗?
  • 好的,虽然我认为使用 SA 表达式看起来更好。不知道为什么将字符串和 args 直接传递给 execute() 不起作用,但在使用 text() 构造时会起作用。将扩展我的示例。
  • 我也同意 SA 表达式看起来更干净,但在我使用这样的数组参数的情况下,我通过 4 或 5 个表加入。在我看来,当涉及到这么多的连接时,纯 SQL 更容易阅读和理解。
  • 现在如何将一个值附加到该数组上?
  • @whoKnows 请将您的问题作为一个单独的问题发布,而不是在无关问题的答案中发布。
【解决方案2】:

在 Flask 中,Survey 表的模型如下所示:

class Survey(UserMixin, db.Model):
    __tablename__ = 'surveys'
    id = db.Column(db.Integer, primary_key=True)
    question_ids_ordered = db.Column('question_ids_ordered', db.ARRAY(db.Integer))

而你想更新question_ids_ordered字段,你可以像这样使用ORM:

from sqlalchemy.orm.attributes import flag_modified

survery = (Survey
           .query
           .filter(Survey.id == 46)).first()

survery.question_ids_ordered.remove(237)
flag_modified(survery, "question_ids_ordered")
db.session.merge(survery)
db.session.flush()
db.session.commit()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 2021-12-25
    相关资源
    最近更新 更多