2010-02-04 3 views
1

Я пытаюсь разрешить пользователям «любимые» различные элементы в моем веб-приложении. Так, например, пользователь может любить комментарий и любить новость. Затем я хочу запросить все элементы, которые пользователь предпочитает, и загружать связанные объекты (будь то новости или комментарий и т. Д.) Полиморфно, чтобы отобразить список объектов для пользователя. Я знаю, как создать один-один полиморфные отношения, однако мне не удалось найти много для многих.sqlalchemy polyorphic many to many relation

Заранее спасибо

EDIT

В моих один-к-одному полиморфных отношениях у меня есть один-много отношения между пользователями и действиями пользователя, и один-один полиморфный связи между действиями пользователя, так и объект, действие было выполнено. Так что в этом случае моя таблица действий пользователя, как так:

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. Я вижу две разумные способы, чтобы сделать это полиморфный:

  1. Используйте отдельную промежуточную таблицу для каждого класса модели Добавлен в избранное и определяют различные отношения в каждой UserAction подклассов.
  2. Определите отдельный внешний ключ для каждой оплодотворенной модели в промежуточной таблице и сопоставьте ее с иерархией классов с наследованием на одну таблицу (что-то вроде 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 
+0

Спасибо за ответ. Думаю, я понимаю, к чему вы клоните, но я не совсем понимаю, как это реализовать. Не могли бы вы привести более конкретный пример, возможно, путем настройки моделей, которые я представил выше?Допустим, у меня есть таблица user_action, таблица новостей и таблица комментариев, где новости и комментарии полиморфны в таблице user_action. Как работают таблицы и картографы? Огромное спасибо. – Marc