通过另一个(声明性)建立sqlalchemy关系

1 投票
1 回答
2697 浏览
提问于 2025-04-15 21:33

有没有人了解ActiveRecord中的“has_many :through”关系?我对Rails不是很熟悉,但我基本上就是想做这个。

举个简单的例子,考虑一下项目、程序员和任务:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from sqlalchemy import Column, ForeignKey
from sqlalchemy.types import Integer, String, Text
from sqlalchemy.orm import relation

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

class Assignment(Base):
    __tablename__ = 'assignment'
    id = Column(Integer, primary_key=True)
    description = Column(Text)

    programmer_id = Column(Integer, ForeignKey('programmer.id'))
    project_id = Column(Integer, ForeignKey('project.id'))

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

    def __repr__(self):
        return '<Assignment("%s")>' % self.description

class Programmer(Base):
    __tablename__ = 'programmer'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

    assignments = relation("Assignment", backref='programmer')

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

    def __repr__(self):
        return '<Programmer("%s")>' % self.name

class Project(Base):
    __tablename__ = 'project'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))
    description = Column(Text)

    assignments = relation("Assignment", backref='project')

    def __init__(self, name=name, description=description):
        self.name = name
        self.description = description

    def __repr__(self):
        return '<Project("%s", "%s...")>' % (self.name, self.description[:10])

engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

项目可以有很多任务。

程序员也可以有很多任务。(这说得太轻了吧?)

不过在我办公室,程序员还可以有很多项目——我希望这个关系能通过分配给程序员的任务来推断出来。

我希望程序员模型有一个属性“projects”,这个属性会返回与程序员通过任务模型相关联的项目列表。

me = session.query(Programmer).filter_by(name='clay').one()
projects = session.query(Project).\
    join(Project.assignments).\
    join(Assignment.programmer).\
    filter(Programmer.id==me.id).all()

我该如何用sqlalchemy的声明式语法清晰简单地描述这个关系呢?

谢谢!

1 个回答

4

我看到有两种方法:

  1. 定义一个关系 Programmer.projects,并设置 secondary='assignment'

  2. 我把 Assignment.project 定义为一个关系,然后把 Programmer.projects 定义为 association_proxy('assignments', 'project')(你可能还想定义一个创建者)。想了解更多信息,可以查看简化关联对象关系这一章节。

撰写回答