sqlalchemy辅助表与复合键

时间:2016-02-04 22:35:29

标签: python sql postgresql sqlalchemy

我有一个多客户平台,可以有几个标签的人,并说一个带有一个标签的foo对象。我不希望每个客户的用户与其他客户分享他们的联系人(人)或标签或foo。每个标签名称对每个客户都是唯一的。

我如何才能拥有标签的复合键(name,customer_name)以及人与标签之间的 n-m关系

我试过了:

enter image description here

person_label_table = Table('person_label', Base.metadata,
                       Column('person_id', Integer, ForeignKey('person.id'), primary_key=True),
                       Column('name', Unicode(32), ForeignKey('label.name'), primary_key=True),
                       Column('customer_name', String(32), ForeignKey('label.customer_name'), primary_key=True)
                       )

class Person(Base, SaveMixin):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    labels = relationship('Label', secondary=person_label_table)

class Label(Base, SaveMixin):
    __tablename__ = 'label'
    name = Column(Unicode(32), primary_key=True)
    customer_name = Column(String(32), ForeignKey('customer.name'), primary_key=True)
    color = Column(String(32))

但我有这个错误:

sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'label' and 'person_label'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.

我还尝试使用更经典的链接表person_label(label_id,person_id)并在标签上添加ID,但是当我使用标签session.merge()时,必须将标签ID加载到前端网络上id)我有:

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: label.name, label.customer_name [SQL: 'INSERT INTO label (name, customer_name, color) VALUES (?, ?, ?)'] [parameters: ('foo', 'bar', 'grey')]

所以你会如何处理这个案子?

感谢您的时间。

编辑 : 为了防止在Brendan Abel响应和显示的代码之后它有所帮助,我有这个错误:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Person.labels - there are multiple foreign key paths linking the tables via secondary table 'person_label'.  Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference from the secondary table to each of the parent and child tables.

所以我亲自更改了标签的定义:

labels = relationship('Label', secondary=person_label_table, foreign_keys=[id]):

但我当时有:

sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship Person.labels - there are no foreign keys linking these tables via secondary table 'person_label'.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' and 'secondaryjoin' expressions.

我最终得到了(在person上添加了primaryjoin / secondaryjoin并删除了复合键上的ForeignKey):

class Person(Base, SaveMixin):
    __tablename__ = 'person'
    labels = relationship('Label', secondary=person_label_table,
                      primaryjoin='and_(Person.id == person_label.c.person_id)',
                      secondaryjoin='and_(person_label.c.name == Label.name, person_label.c.customer_name == Label.customer_name)')

person_label_table = Table('person_label', Base.metadata,
                       Column('person_id', Integer, ForeignKey('person.id'), primary_key=True),
                       Column('name', Unicode(32), primary_key=True),
                       Column('customer_name', String(32), primary_key=True),
                       ForeignKeyConstraint(['name', 'customer_name'], ['label.name', 'label.customer_name'])
                       )

1 个答案:

答案 0 :(得分:2)

您必须使用ForeignKeyConstraint

明确指出复合关系
person_label_table = Table('person_label', Base.metadata,
    Column('person_id', Integer, ForeignKey('person.id'), primary_key=True),
    Column('name', Unicode(32), primary_key=True),
    Column('customer_name', String(32), primary_key=True),
    ForeignKeyConstraint(['name', 'customer_name'], ['label.name', 'label.customer_name'])
)

docs提供了一些例子。

  

重要的是要注意ForeignKeyConstraint是唯一的方法   定义复合外键。虽然我们也可以放置   invoice_item.invoice_id和。上的各个ForeignKey对象   invoice_item.ref_num列,SQLAlchemy不会意识到这些   两个值应该配对在一起 - 它将是两个人   外键约束而不是单个复合外键   引用两列。