一尘不染

使用ID而不是对象填充SQLAlchemy多对多关系

sql

情况:

因此,我在SQLAlchemy中使用关联表具有基本的多对多关系。
例如,一个人可以参加许多聚会,而一个聚会可以有许多人作为客人:

class Person(Base):
    __tablename__ = 'person'
    id      = Column(Integer, primary_key=True)
    name    = db.Column(db.String(50))


class SexyParty(Base):
    __tablename__ = 'sexy_party'
    id      = Column(Integer, primary_key=True)
    guests  = relationship('Person', secondary='guest_association',
                        lazy='dynamic', backref='parties')

guest_association = Table(
    'guest_association',
    Column('user_id',       Integer(), ForeignKey('person.id')),
    Column('sexyparty.id',  Integer(), ForeignKey('sexyparty.id'))
)

通常,如果我想添加参加聚会的嘉宾列表,我会执行以下操作:

my_guests = [prince, olivia, brittany, me]
my_party.guests = guests
db.session.commit()

…其中prince,olivia和brittany都是<Person>实例,而my_party是<SexyParty>实例。

我的问题

我想使用个人ID而不是实例将客人添加到聚会中。例如:

guest_ids = [1, 2, 3, 5]
my_party.guests = guest_ids  # <-- This fails, because guest_ids
                             # are not <Person> instances

我总是可以从数据库中加载实例,但这将导致不必要的DB查询,只是为了设置简单的多对多关系。

我将如何.guests使用person_id的列表来设置属性?必须有一种简单的方法来执行此操作,因为关联表最终还是使用ID来表示多对多关系…

在此先感谢,希望问题清楚。


阅读 109

收藏
2021-03-17

共1个答案

一尘不染

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Person(Base):
    __tablename__ = 'person'
    id      = Column(Integer, primary_key=True)
    name    = Column(String(50))


class SexyParty(Base):
    __tablename__ = 'sexy_party'
    id      = Column(Integer, primary_key=True)
    guests  = relationship('Person', secondary='guest_association',
                        lazy='dynamic', backref='parties')

guest_association = Table(
    'guest_association', Base.metadata,
    Column('user_id',       Integer(), ForeignKey('person.id'), primary_key=True),
    Column('sexyparty_id',  Integer(), ForeignKey('sexy_party.id'), primary_key=True)
)


e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

sess = Session(e)

p1 = Person(id=1, name='p1')
p2 = Person(id=2, name='p2')
p3 = Person(id=3, name='p3')
p4 = Person(id=4, name='p4')

sp1 = SexyParty(id=1)

sess.add_all([sp1, p1, p2, p3, p4])
sess.commit()

# method one.  use insert()
sess.execute(guest_association.insert().values([(1, 1), (2, 1)]))

# method two.  map, optional association proxy
from sqlalchemy.ext.associationproxy import association_proxy

class GuestAssociation(Base):
    __table__ = guest_association
    party = relationship("SexyParty", backref="association_recs")

SexyParty.association_ids = association_proxy(
                    "association_recs", "user_id",
                    creator=lambda uid: GuestAssociation(user_id=uid))

sp1.association_ids.extend([3, 4])
sess.commit()
2021-03-17