【问题标题】:How can I decouple objects from a SQLAlchemy session such that I can insert them into a different database?如何将对象与 SQLAlchemy 会话分离,以便将它们插入到不同的数据库中?
【发布时间】:2015-12-01 03:09:14
【问题描述】:

我有两个数据库(srcdst),每个数据库都使用相同的 SQLAlchemy 模型。我想查询src 并将该查询的结果插入dst

当我尝试将src 中的值插入dst 时,我的代码会引发InvalidRequestError 异常,因为查询的对象附加到src 会话。

#!/usr/bin/env python

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.exc import InvalidRequestError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()


class User(Base):
    __tablename__ = 'users'

    uid = Column(Integer, primary_key=True)
    username = Column(String, unique=True, nullable=False)
    gid = Column(Integer, nullable=False)
    password = Column(String)
    gecos = Column(String)
    home_directory = Column(String)
    shell = Column(String)

    def __init__(self, passwd_string):
        passwd_fields = passwd_string.split(':')
        self.username = passwd_fields[0]
        self.password = passwd_fields[1]
        self.uid = passwd_fields[2]
        self.gid = passwd_fields[3]
        self.gecos = passwd_fields[4]
        self.home_directory = passwd_fields[5]
        self.shell = passwd_fields[6]


def get_session(db_uri):
    engine = create_engine(db_uri)
    Base.metadata.create_all(engine)
    return sessionmaker(bind=engine)()


def add_users(session, user_list):
    session.add_all(user_list)
    session.commit()


def main():
    users = [
        User('root:x:0:0:Root User:/:/bin/bash'),
        User('genuser:x:100:100:Generic User:/home/user:/bin/bash')
    ]

    # insert users to src database
    src = get_session('sqlite:///src.sqlite')
    add_users(src, users)

    # query src database for users
    src_users = src.query(User).all()

    # insert users found in src database into dst database
    try:
        dst = get_session('sqlite:///dst.sqlite')
        add_users(dst, src_users)
    except InvalidRequestError as error:
        print "InvalidRequestError: {}".format(error)


if __name__ == "__main__":
    main()

运行上述代码会产生以下异常/错误:

InvalidRequestError: Object '<User at 0x10bc10250>' is already attached to session '1' (this is '2')

针对@Deepak 的回答,我在User 中实现了copy() 方法:

def copy(self):
    return User(
        '{}:{}:{}:{}:{}:{}:{}'.format(
            self.username,
            self.password,
            self.uid,
            self.gid,
            self.gecos,
            self.home_directory,
            self.shell
        )
    )

这意味着我现在可以做到:

try:
    dst = get_session('sqlite:///dst.sqlite')
    dst.add(user.copy()) for user in src_users
except InvalidRequestError as error:
    print "InvalidRequestError: {}".format(error)

【问题讨论】:

标签: python sqlalchemy


【解决方案1】:

您正在尝试通过数据库 1 的会话进行查询,并将此会话的附加用户对象插入另一个会话。 更好的方法是以与插入第一个表相同的方式在第二个表中插入值。 所以从表 1 中获取值:

src_users = src.query(User).all()
duplicate_records = []
for row in src.query(User).all(): 
    duplicate_user.append(User(row.username +":"+ row.password +":"+str(row.uid)+":"+str(row.gid)+":"+row.gecos+":"+row.home_directory+":"+row.shell))

然后将此列表插入到您的第二个表中。

【讨论】:

  • 我希望有更优雅的东西,但看起来这是最简单的解决方案。因此,我在 User 中实现了一个copy() 方法,该方法返回一个新实例化的 User 对象,该对象由成员变量构造而成。
猜你喜欢
  • 1970-01-01
  • 2019-05-02
  • 1970-01-01
  • 2021-12-23
  • 2014-01-30
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多