1

我有一张Users桌子和一张Tasks桌子。该Tasks表有一个“作者”列和一个“受让人”列,这两个列都是 中唯一 ID 的外键Users

如您所料,这产生了一个错误:“无法确定关系 Users.created_tasks 上的父/子表之间的连接条件 - 有多个外键路径链接这些表。”

如果我想在表中同时包含“作者”和“受让人”,还有什么方法可以同时记录“作者”和“受让人”?

class Tasks(db.Model):
    // ...
    author = db.Column(db.Integer, db.ForeignKey('users.id'))
    assignee = db.Column(db.Integer, db.ForeignKey('users.id'))

class Users(db.Model, UserMixin):
    // ...
    created_tasks = db.relationship('Tasks', backref = 'ctasks_user')
    assigned_tasks = db.relationship('Tasks', backref = 'atasks_user')
4

1 回答 1

1

您可以指定primaryjoin每个属性relationship以区分两者:

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker

connection_uri = (
    "mssql+pyodbc://@localhost:49242/myDb?driver=ODBC+Driver+17+for+SQL+Server"
)
engine = sa.create_engine(connection_uri)

with engine.begin() as conn:
    conn.execute(sa.text("DROP TABLE IF EXISTS task_t"))
    conn.execute(sa.text("DROP TABLE IF EXISTS user_t"))

Base = declarative_base()


class Task(Base):
    __tablename__ = "task_t"
    id = sa.Column(sa.Integer, primary_key=True)
    description = sa.Column(sa.String(50))
    author = sa.Column(sa.Integer, sa.ForeignKey("user_t.id"))
    assignee = sa.Column(sa.Integer, sa.ForeignKey("user_t.id"))

    def __repr__(self):
        return f"<Task(id={self.id}, description='{self.description}')>"


class User(Base):
    __tablename__ = "user_t"
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String(50))
    created_tasks = relationship(
        Task,
        primaryjoin="User.id == Task.author",
        backref="user_created_tasks",
    )
    assigned_tasks = relationship(
        Task,
        primaryjoin="User.id == Task.assignee",
        backref="user_assigned_tasks",
    )

    def __repr__(self):
        return f"<User(id={self.id}, name='{self.name}')>"


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

homer = User(name="Homer")
bart = User(name="Bart")
lisa = User(name="Lisa")

session.add_all([homer, bart, lisa])
session.commit()

mow_the_lawn = Task(
    description="Mow the lawn", author=homer.id, assignee=bart.id
)
wash_the_car = Task(
    description="Wash the car", author=homer.id, assignee=lisa.id
)
session.add_all([mow_the_lawn, wash_the_car])
session.commit()

with engine.begin() as conn:
    result = conn.execute(
        sa.text("SELECT * FROM user_t ORDER BY id")
    ).fetchall()
    print(result)
    # [(1, 'Homer'), (2, 'Bart'), (3, 'Lisa')]
    
    result = conn.execute(
        sa.text("SELECT * FROM task_t ORDER BY id")
    ).fetchall()
    print(result)
    # [(1, 'Mow the lawn', 1, 2), (2, 'Wash the car', 1, 3)]

print(homer.created_tasks)
# [ <Task(id=1, description='Mow the lawn')>, <Task(id=2, description='Wash the car')>]

print(bart.assigned_tasks)
# [ <Task(id=1, description='Mow the lawn')>]
于 2020-07-04T13:52:02.410 回答