2012-01-31 3 views
1

Скажем, у меня есть SQLAlchemy модель что-то вроде этого: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 как удобства, так что я можно пропустить шаг отрываясь идентификатор или объект EmployeeType, если у меня есть имя типа:

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

такая вещь возможна?

EDIT: Я обнаружил, что 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.

ответ

1

Я согласен с общим подходом Джонатана, но я чувствую, как добавить объект работника к сессии и установив тип сотрудника должны быть независимыми операциями. Вот реализация, которая имеет 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() 
+0

В качестве упражнения, я также взбитая версию, которая позволяет устанавливать type_name перед установкой Работника к сессии, путем присоединения " after_attach "для сеанса: https://gist.github.com/1750520 –

2

Я сделал бы это, создав метод, который сделает это для меня.

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')