我正在尝试允许用户在我的网络应用中“喜欢”不同的项目。因此,例如,用户可以喜欢评论并喜欢新闻故事。然后,我想查询用户所喜爱的所有项目,并以多态方式加载相关对象(无论是新闻报道还是评论等),以向用户显示对象列表。我知道如何创建一对一的多态关系,但是我无法弄清楚多少关系。
提前致谢
修改
在我的一对一多态关系中,我在用户和用户操作之间存在一对多关系,并且用户操作与执行操作的对象之间存在一对一的多态关系。所以在这种情况下我的用户操作表是这样的:
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外键位于新闻表中。如果我想创建一个多对多的多态关系,其中多个不同的对象类型可以被许多用户收藏,我将如何去做呢?非常感谢。
答案 0 :(得分:2)
您的示例定义了UserAction
和News
之间的一对多关系。这看起来很糟糕,因为我认为没有理由News
继承UserAction
。要允许多个用户操作引用单个新闻,您必须使用两个外键定义中间表:一个引用UserAction
,另一个引用News
。我认为有两种合理的方法可以使其具有多态性:
UserAction
子类中定义不同的关系。UserActionItem
,UserActionNewsItem
等。)。但请注意,以上所有内容都是为了链接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