2012-03-15 4 views
1

Мне нужна помощь с пониманием того, как наследование работает в SQLAlchemy. Я создал базовый класс для пользователя с некоторыми базовыми функциями. А затем некоторые конкретные пользователи (admin, cooluser, uncooluser). Каждый из них имеет уникальную функциональность, поэтому я решил использовать наследование в SQLAlchemy. Проблема в том, что мне нужно иметь возможность обновлять пользователя до cooluser или uncooluser и в любое время понижать рейтинг пользователя cooluser.Проблема наследования в SQLAlchemy

class User(Base): 
    __tablename__ = 'tbl_users' 
    __table_args__ = {'mysql_engine': 'InnoDB'} 

    user_id = Column(Integer, primary_key = True, unique = True, nullable = False) 
    user_name = Column(String(100), nullable = False, unique = True) 
    password = Column(String(100), nullable = False) 
    user_type = Column('user_type', String(50)) 
    first_name = Column(String(50), nullable = False) 
    last_name = Column(String(50), nullable = False) 
    address = Column(String(50), nullable = False) 
    city = Column(String(20), nullable = False) 
    postal_code = Column(String(10), nullable = False) 
    country_id = Column(Integer, ForeignKey(Contries.country_id)) 

    country = relationship('Country', backref = 'users') 

    query = Session.query_property() 

    __mapper_args__ = {'polymorphic_on': user_type, 'polymorphic_identity': 'User'} 
class CoolUser(User): 
    __tablename__ = 'tbl_cool_user' 
    __table_args__ = {'mysql_engine': 'InnoDB'} 
    __mapper_args__ = {'polymorphic_identity': 'CoolUser'} 

    cool_user_id = Column(Integer, ForeignKey(User.user_id, ondelete = 'CASCADE'), primary_key = True) 
    cool_user_balance = Column(Numeric(15, 3)) 

Могу ли я создать CoolUser без создания новой строки в «tbl_users», но использовать существующий? Можно изменить некоторые настройки, чтобы при удалении CoolUser он просто удалял запись в 'tbl_cool_user', а не 'tbl_user'?

Я пропустил точку наследования в SQLAlchemy?

ответ

0

Вы должны использовать Concrete Table Inheritance. Весь общий атрибут в базовой таблице и создать 2 разных CoolUser и UnCoolUser.

+0

Спасибо за ответ, но я до сих пор путаю. Как изменить тип 'User' на' CoolUser'? Если я создам новый «CoolUser», он будет дублировать «Пользователь» в таблице «CoolUser»? – hitripekac

+0

Пожалуйста, проверьте пример и попробуйте 'polymorphic_on'. Если вы получите какую-либо ошибку, напишите эту ошибку, чтобы мы могли ее решить. – Nilesh

+0

База данных с определенной моделью уже существует и не может быть изменена, потому что есть уже другое программное обеспечение, которое подключается к ней. Я попытался сделать код python так, чтобы он соответствовал этой модели. Мне придется переосмыслить все это ... Я благодарен за помощь. – hitripekac

1

Я не думаю, что вы должны использовать «polymorphic_on» и «polymorphic_identity» в той же таблице. Что вам нужно сделать, это создать базовую таблицу User, содержащую все пользователи (т.е. с mapper_args «polymorphic_on»), то CoolUser наследнике, что (с «polymorphic_identity»):

class User(Base): 
    ... 
    __mapper_args__ = {'polymorphic_on': user_type} 

class CoolUser(User): 
    ... 
    __mapper_args__ = {'polymorphic_identity': 'CoolUser'} 

Затем вы можете изменить user_type, как вам нравится ,

+2

Если «Пользователь» не является абстрактным классом, нужно также «polymorhic_identity» также в таблице «Пользователь». – van

+0

Более подробный пример: https://stackoverflow.com/questions/1337095/sqlalchemy-inheritance –

6

Я пропустил точку наследования в SQLAlchemy?

Я думаю, что вы неправильно используете концепцию inheritance и даже не в особенности реализации SA.
В классическом стиле иерархии вы бы даже подумали, что Кошка будет до собаке или даже определенному типу Собаки? Я так не думаю. Кроме того, я вполне могу себе представить, что некоторые CoolUser также могут быть Administrator в то же время. Как вы разрешите этот тип отношений?

Следовательно, для ваших требований наследование - это просто не концепция использования этой модели изменения состояния. Я бы предложил google для User-Role типа отношений и реализаций. Вам все равно придется решить проблему хранения данных, связанных с ролями.


Как @aquavitae упоминалось: в SA, вы можете взломать вокруг и изменить user_type. Но следует помнить, что в этом случае происходит следующее:

  • при загрузке объекта из базы данных, его класс будет отражать новый тип (ХОРОШО)
  • когда вы понижаете объект (от CoolUser для пользователя), строка, которая соответствует CoolUser, будет не удалена (я думаю, что это BAD, но это может быть ОК)
  • при обновлении объекта (от пользователя до CoolUser) нет новой строки для таблицы CoolUser будет создано, и все ваши значения будут NULL. Таким образом, установка/добавление любого свойства, которое хранится в неустановленной строке, приведет к хорошей ошибке.И когда запросы для конкретного подкласса, вы получите не, возвратите объект обратно, поскольку INNER JOIN используется для извлечения объекта. (BAD)
  • в целом, не меняет кошку к собаке
+2

+1 Я должен был поставить все эти оговорки в свой ответ тоже! В этом случае, вероятно, лучше просто запросить пользователей с фильтром. – aquavitae

+1

Спасибо. Думаю, мне придется переосмыслить все это. Причина, по которой я считал, что наследование будет подтаблицей, заключается в том, что каждый пользователь ('CoolUser',' UnCoolUser', 'Admin') должен войти в систему, выйти из системы и т. Д. Но я думаю, что я ошибся ... – hitripekac

+0

Я бы предложил вам создать отдельную таблицу для задач, ориентированных на логин (назовем ее «Пользователь»), и создать иерархию (например, «Лицо (-> CoolPerson, -> UncoolPerson, -> Distributor) ') для вашей модели данных, а затем иметь внешний ключ на' Person.user_id' (вы даже можете использовать одно и то же значение ID). В этом случае «Администратор», вероятно, все еще будет «ролью» (или просто флагом в таблице «Пользователь») и будет связан только с таблицей «Пользователь», не зная ничего о «Человеке» и его потомках. – van

Смежные вопросы