【问题标题】:sqlalchemy polymorphic many to many relationsqlalchemy 多态多对多关系
【发布时间】:2010-02-14 01:23:30
【问题描述】:

我试图让用户在我的网络应用程序中“收藏”不同的项目。因此,例如,用户可以收藏评论和收藏新闻故事。然后我想查询用户收藏的所有项目,并以多态方式加载关联的对象(无论是新闻故事还是评论等)以向用户显示对象列表。我知道如何创建一对一的多态关系,但是我无法弄清楚多对多。

提前致谢

编辑

在我的一对一多态关系中,用户和用户操作之间是一对多的关系,用户操作和执行操作的对象之间是一对一的多态关系。所以在这种情况下,我的用户操作表是这样的:

class UserAction:  
  pass

user_actions = Table('user_action', metadata,  
    Column('id', Integer, autoincrement=True, primary_key=True),
    Column('module', String(30)),
    Column('created', DateTime, default=datetime.now),  
    Column('user_id', Integer, ForeignKey('user.id'))  
)

新闻表(可以通过用户操作访问的对象之一):

class News:  
  pass

news = Table('news', metadata,  
    Column('id', Integer, autoincrement=True, primary_key=True),  
    Column('title', String(30), nullable=False),  
    Column('action_id', Integer, ForeignKey('user_action.id'))  
)

还有映射器:

mapper(UserAction, user_actions, polymorphic_on=user_actions.c.module, polymorphic_identity='user_action')  
mapper(News, news, inherits=UserAction, polymorphic_identity='news')

如您所见,新闻对象和与之关联的 user_action 记录之间存在明确的一对一关系。这是因为 user_action 外键在 news 表中。如果我想创建一个多对多多态关系,其中多个不同的对象类型可以被许多用户喜爱,我将如何去做呢?非常感谢。

【问题讨论】:

  • 从一对一创建多态模型的多对多关系没有区别。您能否更精确或发布不起作用的代码示例或您想适应?

标签: polymorphism sqlalchemy


【解决方案1】:

您的示例定义了UserActionNews 之间的一对多关系。这对我来说看起来很乱,因为我看不出News 继承自UserAction 的原因。要允许引用单个新闻的多个用户操作,您必须使用两个外键定义中间表:一个引用 UserAction,另一个引用 News。我看到了两种合理的方法来使它成为多态:

  1. 为每个喜欢的模型类使用单独的中间表,并在每个 UserAction 子类中定义不同的关系。
  2. 为中间表中的每个首选模型定义单独的外键,并将其映射到具有单表继承的类层次结构(例如UserActionItemUserActionNewsItem 等)。

但请注意,以上所有内容都是用于链接UserAction 和一些具有多对多关系的入门模型。虽然在我看来,用户添加条目更像是将 User 与条目模型链接。

更新:以下是工作示例。我看到的唯一问题是它允许重复。

from sqlalchemy import *
from sqlalchemy.orm import mapper, relation, sessionmaker
from sqlalchemy.ext.associationproxy import association_proxy

metadata = MetaData()

users = Table(
    'users', metadata,
    Column('id', Integer, nullable=False, primary_key=True),
)

news = Table(
    'news', metadata,
    Column('id', Integer, nullable=False, primary_key=True),
)

comments = Table(
    'comments', metadata,
    Column('id', Integer, nullable=False, primary_key=True),
)

favitems = Table(
    'favitems', metadata,
    Column('id', Integer, nullable=False, primary_key=True),
    Column('user_id', Integer, ForeignKey(users.c.id), nullable=False),
    Column('item_type', Integer, nullable=False),
    Column('news_id', Integer, ForeignKey(news.c.id)),
    Column('comment_id', Integer, ForeignKey(comments.c.id)),
)

class News(object): pass

class Comment(object): pass

class FavItem(object):
    TYPE_NEWS = 1
    TYPE_COMMENT = 2
    def __new__(cls, item=None):
        if isinstance(item, News):
            cls = FavNews
        elif isinstance(item, Comment):
            cls = FavComment
        return object.__new__(cls)

class FavNews(FavItem):
    def __init__(self, item):
        self.item_type = self.TYPE_NEWS
        self.item = item

class FavComment(FavItem):
    def __init__(self, item):
        self.item_type = self.TYPE_COMMENT
        self.item = item

class User(object):
    favorites = association_proxy('_favitems', 'item', creator=FavItem)

mapper(News, news)

mapper(Comment, comments)

mapper(FavItem, favitems,
       polymorphic_on=favitems.c.item_type)

mapper(FavNews, favitems,
       inherits=FavItem,
       polymorphic_identity=FavItem.TYPE_NEWS,
       properties={
            'item': relation(News),
       })

mapper(FavComment, favitems,
       inherits=FavItem,
       polymorphic_identity=FavItem.TYPE_COMMENT,
       properties={
            'item': relation(Comment),
       })

mapper(User, users,
       properties={
            '_favitems': relation(FavItem),
       })

engine = create_engine('sqlite://')
metadata.create_all(engine)
session = sessionmaker(engine)()

user = User()
news1 = News()
news2 = News()
comment1 = Comment()
comment2 = Comment()
user.favorites = [news1, news2, comment1, comment2]
session.add(user)
session.commit()
user_id = user.id

session.expunge_all()
user = session.query(User).get(user_id)
print user.favorites

【讨论】:

  • 感谢您的回复。我想我明白你在做什么,但我不太明白如何实现它。您能否通过调整我上面介绍的模型来举一个更具体的例子?假设我有 user_action 表、news 表和一个 cmets 表,其中 news 和 cmets 在 user_action 表上是多态的。表和映射器如何在这里工作?非常感谢。
猜你喜欢
  • 1970-01-01
  • 2012-05-13
  • 2021-06-26
  • 2019-06-22
  • 2016-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多