2013-03-20 6 views
4

Итак, я новичок в этом python и sqlalchemy. Мне нужна помощь с наследованием или, может быть, mixin (но скорее наследование).Наследование python в sqlalchemy

У меня есть psudo код, но я на самом деле не добились никакого прогресса, чтобы получить в любом месте:

Base = declarative_base() 

class ModelBase(Base): 
    """Base model that only defines last_updated""" 
    __tablename__ = 'doesnotexistandtheclassshouldnotbeinstantiated' 

    #all tables inheriting from ModelBase will have this column 
    last_updated = Column(DateTime) 

    def __init__(self, last_updated): 
    self.last_updated = last_updated 

class User(ModelBase): 
    """Defines the user but should also have the last_updated inherited from ModelBase""" 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 

    def __init__(self, ....): 
    ModelBase.__init__(last_updated) 

Я хочу, чтобы все таблицы, унаследовавшие от ModelBase также имеют last_updated. Как мне это сделать?

ОБНОВЛЕНО КОД:

class BaseUserMixin(object): 
    """Base mixin for models using stamped data""" 

    @declared_attr 
    def last_updated(cls): 
     return Column(DateTime) 

    @declared_attr   
    def last_updated_by(cls): 
     return Column(String) 

    def __init__(self, last_updated, last_updated_by): 
     self.last_updated = last_updated 
     self.last_updated_by = last_updated_by 

Base = declarative_base(cls=BaseUserMixin) 


class User(Base): 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    email = Column(String) 
    fullname = Column(String) 
    password = Column(String) 
    enabled = Column(Boolean) 

    def __init__(self, name, fullname, password, email, last_updated, last_updated_by): 
     self.name = name 
     self.fullname = fullname 
     self.password = password 
     self.email = email 
     # goes wrong here 
     super(User, self).__init__(last_updated, last_updated_by) 

    def __repr__(self): 
     return "<User('%', '%', '%', '%', '%', '%')>"\ 
       % (self.name, 
        self.fullname, 
        self.password, 
        self.email, 
        self.last_updated, 
        self.last_updated_by 
       ) 

Ошибка:

_declarative_constructor() takes exactly 1 argument (3 given) 

Что может быть проблема? Я думал, что это работает, но при повторном запуске отладчика это не удалось.

+1

Вы видите этот вопрос? http://stackoverflow.com/questions/1337095/sqlalchemy-inheritance Это, кажется, достаточно хороший ответ. – Magsol

+0

есть. дело в том, что они не связаны, и это не «polymorphic_on» ничего ... – Asken

ответ

6

Решение declared_attr; который будет называться и добавлены к экземплярам DeclarativeMeta в любое время они появляются:

Edit: в __init__ автомагически предоставленный declarative не может вызвать super(). если вы этого хотите, это должно быть последнее, и единственный способ сделать это - использовать обычный миксин.

import datetime 
from sqlalchemy import Column, DateTime, Integer, String 
from sqlalchemy.ext.declarative import declared_attr, declarative_base 

class BaseMixin(object): 
    @declared_attr 
    def last_updated(cls): 
     return Column(DateTime) 

    def __init__(self, last_updated, *args, **kwargs): 
     super(BaseMixin, self).__init__(last_updated=datetime.datetime.now(), *args, **kwargs) 
     print "BaseMixin.__init__" 
     self.last_updated = last_updated 

ModelBase = declarative_base() 

Обратите внимание, что Mixin должен прийти первый!

class User(BaseMixin, ModelBase): 
    """Defines the user but should also have the last_updated inherited from ModelBase""" 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 
    username = Column(String) 

    def __init__(self, *args, **kwargs): 
     super(User, self).__init__(last_updated=datetime.datetime.now(), *args, **kwargs) 
     print "User.__init__" 

if __name__ == '__main__': 
    from sqlalchemy import create_engine 
    from sqlalchemy.orm import sessionmaker 
    engine = create_engine('sqlite:///:memory:', echo=True) 
    ModelBase.metadata.create_all(engine) 
    user = User(username='alice') 

    Session = sessionmaker(engine) 
    session = Session() 
    session.add(user) 
    session.commit() 

Однако; Вы действительно хотите использовать для этого __init__? __init__ не вызывается, когда объекты возвращаются из запросов; и то, что вы действительно хотите, это для столбца до . изменить прямо сейчас., когда он изменен. Вот запеченные в Column() уже:

from sqlalchemy import func 

class BaseMixin(object): 
    @declared_attr 
    def created_date(cls): 
     return Column(DateTime, default=func.now()) 

    @declared_attr 
    def modified_date(cls): 
     return Column(DateTime, default=func.now(), onupdate=func.now()) 

обратно, используя cls= аргумент

ModelBase = declarative_base(cls=BaseMixin) 


class User(ModelBase): 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 
    username = Column(String) 

if __name__ == '__main__': 
    engine = create_engine('sqlite:///:memory:', echo=True) 
    ModelBase.metadata.create_all(engine) 
    user = User(username='alice') 

    Session = sessionmaker(engine) 
    session = Session() 
    session.add(user) 
    session.commit() 

    session = Session() 
    sameuser = session.query(User).one() 
    sameuser.username = 'bob' 
    session.commit() 
+0

Вы имели в виду «def last_updated (cls)»? – Asken

+0

У меня есть чтение, но он работает ... – Asken

+0

Можете ли вы снова посмотреть? Кажется, я не могу заставить его работать. Обновлен код ... – Asken

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