【发布时间】:2019-09-18 21:16:33
【问题描述】:
我有一个 for 循环,它创建一个新的“行”对象,在将对象提交到 Postgres 数据库中的表之前用数据填充属性。我要插入的表(以及对象)采用 UUID 的主键,只有在第一次提交后所有新创建的行对象中的循环的第一次迭代后,这个值保持不变。
我对解决方案有点迷茫,但是我认为这可能与我处理数据库会话的方式有关。在写这篇文章时,我还注意到我在 invite_users 和 invite_user 函数中使用了相同的变量名 (new_user)。虽然 Python 会认为它们在不同的范围内(我认为),但我想知道 SQLALchemy 会话是否会?
请注意,我已经删除了很多我认为在问题上下文中多余的代码 - 主要是更多列等。invite_user 函数也用于其他地方,因此 invite_users 仅用于批量“邀请”。
这是一个 sn-p 显示表类定义的开始和Column 定义:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects import postgresql
import uuid
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(postgresql.UUID(as_uuid=True), default=uuid.uuid4(), primary_key=True)
email = Column(String, unique=True)
这是我用来创建和销毁会话的函数:
from contextlib import contextmanager
from sqlalchemy import create_engine
@contextmanager
def db_session(db_url):
engine = create_engine(db_url, convert_unicode=True)
connection = engine.connect()
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine))
yield db_session
db_session.close()
connection.close()
下面是遍历 JSON 对象数组的函数的一部分:
def invite_users(json_dict):
exceptions = {}
with db_session(environ['CONNECTION_STRING']) as session:
for new_user in json_dict['users']:
try:
invite_user(
session,
info['email_address']
)
# I'm catching exceptions and storing them to handle them later
except Exception as e:
exceptions[user_info['email_address']] = e
pass
这里是 invite_user 函数,它将行添加到会话并尝试提交它:
from project.database import * # this contains the User table class above
from project.exceptions import *
def invite_user(session, email):
new_user = User(
email=email
)
session.add(new_user)
try:
session.commit()
except exc.IntegrityError as e:
session.rollback()
raise DuplicateViolation(f"User already invited") from None
所以我遍历字典 (json_dict['emails']) 中的电子邮件地址。然后,我将每封电子邮件连同当前数据库session 一起传递给邀请用户。我这样做是为了避免为每个invite_user 调用创建一个会话,因为从性能角度来看,它似乎比在invite_user 函数中创建一个新的session 更明智,因为这将导致它们中的许多被创建和销毁。
我认为我的 Column 定义足以处理每次提交 User 行对象时新 UUID 的生成。但是,如果我通过invite_users 函数传递多个电子邮件地址,第一个用户会被添加一个新的 UUID,而第二个用户会被分配相同的 UUID。如果我通过一个电子邮件地址,一切都很好。
我不想依赖在数据库中查询现有行。我完全依靠数据库约束来防止重复,异常处理用于向用户报告错误。
【问题讨论】:
标签: python postgresql sqlalchemy