如何构建不同类型的一对多关系?

时间:2012-04-16 14:07:22

标签: python sqlalchemy

如果我有两个表:A(id,...其他一些列)和B(id,......其他一些列)。我需要将评论(另一个表:id,text,author)与A和B对象相关联。

我是否可以为此目的创建第四个表:comment_id,table_id(A或B或其他),item_id?我的意思是一些sqlalchemy方式?

现在我只知道这两个解决方案: http://bpaste.net/show/27149/ - 对于每个A和B,将有单独的表格和评论。我不认为这是一个好主意,因为那些表(应该)是相同的,如果我想看到一些作者的所有评论 - 它将比其他方式更难,如果有一天会有C表 - 我将需要为其评论创建一个表...

另一种解决方案 - http://bpaste.net/show/27148/。我认为更好,但我仍然需要为每个需要评论项目的表创建一个关联表。

有什么想法吗?提前谢谢。

2 个答案:

答案 0 :(得分:2)

你可以尝试:

class Comment(Base):
    __tablename__ = 'comments'

    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('a.id'), nullable=True)
    b_id = Column(Integer, ForeignKey('b.id'), nullable=True)
    text = Column(UnicodeText, nullable=False)

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

它仍然是一种相对hacky的方式,但它通过使用外键保留了引用完整性。

如果你想找到存储表名的解决方案,你可以尝试这样的事情:

class A(Base):
    __tablename__ = 'as'

    id = Column(Integer, primary_key=True)
    name = Column(Unicode, nullable=False, unique=True)
    comments = relationship("Comment",
                    primaryjoin="and_(A.id==Comment.id, "
                        "Comment.model=='A')")

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

class Comment(Base):
    __tablename__ = 'comments'

    id = Column(Integer, primary_key=True)
    text = Column(UnicodeText, nullable=False)
    model = Column(String(50), nullable=False)

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

我自己没有测试过,所以如果遇到问题,请查看Specifying Alternate Join Conditions或评论,我会做更多研究。

有关该主题的深入说明,请参阅Mike Bayer's blog entry on Polymorphic Associations

答案 1 :(得分:0)

我也会选择第二种解决方案。但是,正如您所说,可能会有第三个表C,那么您可以将B_CommentA_Comment作为字段放在一个关联表中,例如:

class Comment(Base):
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('as.id'), primary_key=True, nullable=True)
    b_id = Column(Integer, ForeignKey('bs.id'), primary_key=True, nullable=True)
    text = Column(UnicodeText, nullable=False)
    # ...

您可以使用以下查询:session.query(Comment).filter_by(a=whatever)

我想您可以添加某种约束,以便a_idb_id不同时NULL

这是另一种方法(我不知道它是否是标准方式,但它应该有用......

class Letter(Base):
    id = ...

class A(Base):
    letter_id = Column(Integer, ForeignKey('letters.id'), primary_key=True, nullable=False)
    # ...

class Comment(Base):
    letter_id = Column(Integer, ForeignKey('letters.id'), primary_key=True, nullable=True)
    # ...