2014-10-08 75 views
1

我正在为我的项目使用sqlalchemy。我对定义模型有困难的逻辑。如何为困难逻辑定义sqlalchemy orm模型

我有四个数据库表

item_type 
- item_type_id(tinyint) 
- item_type_name (varchar) --item_types can be "post(1)", "product(2)" , "gallery(3)" 

tag 
- tag_id(int) 
- tag_name(varchar) 

item_tag 
- item_type_id (tinyint) 
- item_id (int) -- item_id is can be post_id or product_id or gallery_id 
- tag_id(int) 

post 
- post_id 
- post_title 
- post_content 

我的模型

class Tag(Base): 
    __tablename__ = 'tag' 

    tag_id = Column(Integer, primary_key=True) 
    tag_name = Column(String(255)) 


class Post(Base): 
    __tablename__ = 'post' 

    post_id = Column(Integer, primary_key=True) 
    post_title = Column(String(255)) 
    post_title = Column(Text) 

    #tags relation will be here 


class ItemTag(Base): 
    __tablename__ = 'item_tag' 

    item_type_id = Column(Integer, primary_key=True) 
    item_id = Column(Integer, primary_key=True) 
    tag_id = Column(Integer, ForeignKey("tag.tag_id"), primary_key=True) 

得到后标记SQL(POST_ID = 12)

SELECT TAG.* 
FROM item_tag IT 
INNER JOIN tag TAG ON IT.tag_id=TAG.tag_id 
WHERE IT.item_type_id=1 AND IT.item_id=12 

我不知道如何定义relati在Post模型中标记。邮政标签关系的正确方法是什么?

+0

即使您定义了这种关系(使用'primaryjoin','secondaryjoin'和'secondary'')并且能够执行查询('select'),您将无法处理添加新的'Tag's到项目。 – van 2014-10-09 06:05:22

+0

请查看[通用关联](http://docs.sqlalchemy.org/en/rel_0_9/orm/examples.html#module-examples.generic_associations)示例,以便让您了解您需要实现的功能整个逻辑透明。 – van 2014-10-09 06:06:21

回答

1

可以使用primaryjoin参数orm.relationship()指定复杂的连接条件:http://docs.sqlalchemy.org/en/rel_0_9/orm/relationships.html#relationship-primaryjoin

针对您的特殊情况下,您将定义类似如下:

from sqlalchemy import orm 

class Post(Base): 
    ... 
    tags = orm.relationship('Tag', 
     primaryjoin='and_(ItemTag.tag_id==Tag.tag_id, ItemTag.item_id==Post.post_id, ItemTag.item_type_id==1)') 

我没有测试过这可能需要一些修改,但希望这足以让你走上正确的轨道。

+0

谢谢。我补充说,工作>>标签=关系('ItemTag',primaryjoin =“and_(Post.post_id == foreign(ItemTag.item_id),ItemTag.item_type_id == 2)”) – Alexander 2014-10-09 06:33:01

1

@dgilland的回答后,我找到了两个解决方案。

溶液1

class Post(Base): 
    __tablename__ = "post" 

    tags = relationship('ItemTag', primaryjoin = "and_(Post.post_id==foreign(ItemTag.item_id), ItemTag.item_type_id==2)") 

class ItemTag(Base): 
    __tablename__ = 'item_tag' 

    item_type_id = Column(Integer, primary_key=True) 
    item_id = Column(Integer, primary_key=True) 
    tag_id = Column(Integer, ForeignKey("tag.tag_id"), primary_key=True) 
    tag = relationship(Tag, lazy="joined") 

溶液2(I选择这种溶液)

ItemTag = Table("item_tag", Base.metadata, 
    Column("item_type_id", Integer, primary_key=True), 
    Column("item_id", Integer, primary_key=True), 
    Column("tag_id", Integer, ForeignKey("tag.tag_id"), primary_key=True) 
) 

class Post(Base): 
    __tablename__ = "post" 

    tags = relationship('Tag', 
      secondary=ItemTag, 
      primaryjoin=ItemTag.c.tag_id==Tag.tag_id, 
      secondaryjoin = and_(post_id==foreign(ItemTag.c.item_id), ItemTag.c.item_type_id==2, ItemTag.c.tag_id==Tag.tag_id), 
      backref=backref('posts', lazy="dynamic") 
     ) 

都工作。