SqlAlchemy 与特定列的关系

发布于 2025-01-01 07:19:00 字数 1326 浏览 0 评论 0原文

假设我有一个像这样的 SqlAlchemy 模型:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
Session = sessionmaker()

class EmployeeType(Base):
    __tablename__ = 'employee_type'
    id = Column(Integer(), primary_key=True)
    name = Column(String(20))

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer(), primary_key=True)
    type_id = Column(Integer(), ForeignKey(EmployeeType.id))
    type = relationship(EmployeeType, uselist=False)

session = Session()
session.add(EmployeeType(name='drone'))
session.add(EmployeeType(name='PHB'))

为了方便起见,我希望有某种从 Employee 直接到 EmployeeType.name 的“关系”,所以如果我有的话,我可以跳过查找 id 或 EmployeeType 对象的步骤类型名称:

emp = Employee()
emp.type_name = "drone"
session.add(emp)
session.commit()
assert (emp.type.id == 1)

这样的事情可能吗?

编辑:我发现association_proxy可以让我中途:

class Employee(Base):
    ...
    type_name = association_proxy("type", "name")

唯一的问题是,如果我分配给它:

emp = session.query(Employee).filter_by(EmployeeType.name=='PHB').first()
emp.type_name = 'drone'

它会修改employee_type.name列,而不是employee.type_id列。

Say I have a SqlAlchemy model something like this:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
Session = sessionmaker()

class EmployeeType(Base):
    __tablename__ = 'employee_type'
    id = Column(Integer(), primary_key=True)
    name = Column(String(20))

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer(), primary_key=True)
    type_id = Column(Integer(), ForeignKey(EmployeeType.id))
    type = relationship(EmployeeType, uselist=False)

session = Session()
session.add(EmployeeType(name='drone'))
session.add(EmployeeType(name='PHB'))

I'd like to have some kind of "relationship" from Employee directly to EmployeeType.name as a convenience, so I can skip the step of looking up an id or EmployeeType object if I have a type name:

emp = Employee()
emp.type_name = "drone"
session.add(emp)
session.commit()
assert (emp.type.id == 1)

Is such a thing possible?

EDIT: I found that association_proxy can get me partway there:

class Employee(Base):
    ...
    type_name = association_proxy("type", "name")

the only problem being that if I assign to it:

emp = session.query(Employee).filter_by(EmployeeType.name=='PHB').first()
emp.type_name = 'drone'

it modifies the employee_type.name column, not the employee.type_id column.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自由如风 2025-01-08 07:19:00

我同意Jonathan的一般做法,但我觉得向会话中添加员工对象并设置员工类型应该是独立操作。这是一个以 type_name 作为属性的实现,需要在设置之前添加到会话中:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
Session = sessionmaker()

class EmployeeType(Base):
    __tablename__ = 'employee_type'
    id = Column(Integer(), primary_key=True)
    name = Column(String(20))

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer(), primary_key=True)
    type_id = Column(Integer(), ForeignKey(EmployeeType.id))
    type = relationship(EmployeeType)

    @property
    def type_name(self):
        if self.type is not None:
            return self.type.name
        return None

    @type_name.setter
    def type_name(self, value):
        if value is None:
            self.type = None
        else:
            session = Session.object_session(self)
            if session is None:
                raise Exception("Can't set Employee type by name until added to session")
            self.type = session.query(EmployeeType).filter_by(name=value).one()

I agree with Jonathan's general approach, but I feel like adding an employee object to the session and setting the employee type should be independent operations. Here's an implementation that has type_name as a property and requires adding to the session before setting it:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
Session = sessionmaker()

class EmployeeType(Base):
    __tablename__ = 'employee_type'
    id = Column(Integer(), primary_key=True)
    name = Column(String(20))

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer(), primary_key=True)
    type_id = Column(Integer(), ForeignKey(EmployeeType.id))
    type = relationship(EmployeeType)

    @property
    def type_name(self):
        if self.type is not None:
            return self.type.name
        return None

    @type_name.setter
    def type_name(self, value):
        if value is None:
            self.type = None
        else:
            session = Session.object_session(self)
            if session is None:
                raise Exception("Can't set Employee type by name until added to session")
            self.type = session.query(EmployeeType).filter_by(name=value).one()
赤濁 2025-01-08 07:19:00

我会通过创建一个为我做这件事的方法来做到这一点。

class EmployeeType(Base):
    __tablename__ = 'employee_type'
    id = Column(Integer(), primary_key=True)
    name = Column(String(20))

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer(), primary_key=True)
    type_id = Column(Integer(), ForeignKey(EmployeeType.id))
    type = relationship(EmployeeType, uselist=False)

    def __init__(self, type):
        self.type = type

    def add(self, type_name=None):
        if type_name is not None:
            emp_type = DBSession.query(EmployeeType).filter(EmployeeType.name == type_name).first()
            if emp_type:
                type = emp_type
            else:
                type = EmployeeType(name=type_name)
        else:
            type = None
        DBSession.add(Employee(type=type))

然后你就可以:

Employee.add(type_name='boss')

I would do this by creating a method that does this for me.

class EmployeeType(Base):
    __tablename__ = 'employee_type'
    id = Column(Integer(), primary_key=True)
    name = Column(String(20))

class Employee(Base):
    __tablename__ = 'employee'
    id = Column(Integer(), primary_key=True)
    type_id = Column(Integer(), ForeignKey(EmployeeType.id))
    type = relationship(EmployeeType, uselist=False)

    def __init__(self, type):
        self.type = type

    def add(self, type_name=None):
        if type_name is not None:
            emp_type = DBSession.query(EmployeeType).filter(EmployeeType.name == type_name).first()
            if emp_type:
                type = emp_type
            else:
                type = EmployeeType(name=type_name)
        else:
            type = None
        DBSession.add(Employee(type=type))

Then you do:

Employee.add(type_name='boss')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文