你如何使用`secondary`kwarg来适应SqlAlchemy中的这种情况?

时间:2015-07-01 19:58:25

标签: python postgresql orm sqlalchemy

我的情况是用户可以属于许多课程,而课程可以包含许多用户。我把它建模在SqlAlchemy中就像这样:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)


class Course(Base):
    __tablename__ = 'courses'

    id = Column(Integer, primary_key=True)
    archived = Column(DateTime)


class CourseJoin(Base):
    __tablename__ = 'course_joins'

    id = Column(Integer, primary_key=True)

    # Foreign keys
    user_id = Column(Integer, ForeignKey('users.id'))
    course_id = Column(Integer, ForeignKey('courses.id'))

在系统中,我们有能力“存档”课程。这由课程模型上的日期时间字段标记。我想为User模型提供一个名为course_joins的关系,该关系仅包含尚未归档相应Course的CourseJoins。我正在尝试使用secondary kwarg来实现这一点:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)

    course_joins = relationship('CourseJoin',
                                secondary='join(Course, CourseJoin.course_id == Course.id)',
                                primaryjoin='and_(CourseJoin.user_id == User.id,'
                                                 'Course.archived == None)',
                                order_by='CourseJoin.created')

但是我收到了这个错误:

InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers.  Original exception was: FROM expression expected

我相信这是secondary的{​​{1}} kwarg的确切用法,但我不确定发生了什么。

1 个答案:

答案 0 :(得分:1)

如果您真的只有多对多关系(加created)列,我认为定义关系的正确方法是:

courses = relationship(
    'Course',
    secondary='course_joins',
    primaryjoin='users.c.id == course_joins.c.user_id',
    secondaryjoin='and_(courses.c.id == course_joins.c.course_id, courses.c.archived == None)',
    order_by='course_joins.c.created',
    viewonly=True,
)

并使用它:

u1 = User(courses=[Course()])
session.add(u1)
u2 = User(courses=[Course(archived=datetime.date(2013, 1, 1))])
session.add(u2)

否则,只需完全放弃secondary并将其他条件添加到primaryjoin

courses = relationship(
    'CourseJoin',
    primaryjoin=\
    'and_(users.c.id == course_joins.c.user_id, '
    'courses.c.id == course_joins.c.course_id, '
    'courses.c.archived == None)',
    order_by='course_joins.c.created',
)