SqlAlchemy关系到特定列

6

假设我有一个类似于以下的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'))

我希望能够直接从员工到员工类型(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列。

2个回答

4

我赞同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()

作为一项练习,我还编写了一个版本,允许在将Employee附加到会话之前设置type_name,通过将“after_attach”事件侦听器附加到Session:https://gist.github.com/1750520 - Mu Mind

3
我会创建一个方法来完成这个任务。
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')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接