sqlalchemy中的python继承 [英] python inheritance in sqlalchemy

查看:142
本文介绍了sqlalchemy中的python继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我是这个python和sqlalchemy的新手。我需要一些继承的帮助,或者可能是一个mixin(而是继承)。

So I'm new to this python and sqlalchemy. I need some help with inheritance or maybe a mixin (but rather inheritance).

我有一些psudo代码,但我还没有取得任何进展: / p>

I have some psudo code but I haven't really made any progress to get anywhere:

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了。我该怎么做?

I want all tables inheriting from ModelBase to also have last_updated. How would I do that?

更新后的代码:

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)

可能是什么问题?我认为它有效,但是当重新运行调试器时它失败了。

What can be the problem? I thought it was working but when re-running the debugger it failed.

推荐答案

解决方案是 declared_attr ;它将在出现时随时调用并添加到DeclarativeMeta的实例中:

The solution is declared_attr; which will be called and added to instances of DeclarativeMeta anytime they appear:

编辑 __ init __ 自动提供声明无法调用 super()。如果你想要它,它必须是最后,唯一的方法是使用常规mixin。

Edit: the __init__ automagically provided by declarative cannot call super(). if you want it, it has to be last, and the only way to do that is to use a regular mixin.

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 必须先出现

Note that the mixin must come first!

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()已经:

However; Are you sure you want to use __init__ for this in the first place? __init__ is not called when objects are returned from queries; and what you really want is for the column to change to right now when it's modified. That's baked into Column() already:

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()

这篇关于sqlalchemy中的python继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆