Bar*_*rka 4 python abstract-class sqlalchemy python-3.x
以下代码是带有一个简单表的SqlAlchemy ORM的非常简单的实现。Mytable类尝试从BaseAbstract继承。
该代码引发以下异常:
消息:元类冲突:派生类的元类必须是其所有基元元类的(非严格)子类
from abc import ABC
from sqlalchemy import Column, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
class BaseAbstract(ABC):
"""description of class"""
SQLALCHEMY_DATABASE_URI =\
'mssql+pyodbc://(local)/TestDB?driver=SQL+Server+Native+Client+11.0'
SQLALCHEMY_TRACK_MODIFICATIONS = False
engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
metadata = Base.metadata
class Mytable(Base, BaseAbstract):
__tablename__ = 'myTable'
id = Column(Integer, primary_key=True)
firstNum = Column(Integer, nullable=False)
secondNum = Column(Integer, nullable=False)
Run Code Online (Sandbox Code Playgroud)
如果将类声明行更改为
类Mytable(Base):
该代码将正常工作。另外,如果您更改class BaseAbstract(ABC):为class BaseAbstract(object):代码,也可以再次正常工作。如何从SQLAlchemy中的抽象类继承?
混合元类并不容易,应避免使用。SQLAlchemy提供了一种处理抽象基类或扩充基类的方法,另一方面,您尝试执行的操作看起来很像mixin。
您可以使用以下命令指示SQLAlchemy跳过为类创建表和映射器__abstract__:
Base = declarative_base()
class BaseAbstract(Base):
"""description of class"""
__abstract__ = True
class Mytable(BaseAbstract):
...
Run Code Online (Sandbox Code Playgroud)
您也可以增加Base课程:
class BaseAbstract:
"""description of class"""
Base = declarative_base(cls=BaseAbstract)
class Mytable(Base):
...
Run Code Online (Sandbox Code Playgroud)
但是在我看来,最简单的解决方案是完全放弃使用“抽象库”,并将其视为mixin,就像您已经做过的那样:
class CommonMixin:
"""description of class"""
Base = declarative_base()
class Mytable(CommonMixin, Base):
...
Run Code Online (Sandbox Code Playgroud)
但是,如果您坚持使用实际的abc.ABC抽象基类,请将模型类注册为虚拟子类:
class BaseAbstract(ABC):
"""description of class"""
Base = declarative_base()
@BaseAbstract.register
class Mytable(Base):
...
Run Code Online (Sandbox Code Playgroud)
缺点是@abc.abstractmethod在实例化虚拟子类时不检查修饰的方法。
如果上述不符合您的需求,您要使用ABC的检查所需的方法来实现,你可以尝试这样做的指示异常,并创建一个新的元类是组合DeclarativeMeta和ABCMeta:
In [6]: class DeclarativeABCMeta(DeclarativeMeta, abc.ABCMeta):
...: pass
...:
In [7]: Base = declarative_base(metaclass=DeclarativeABCMeta)
In [8]: class BaseAbstract(abc.ABC):
...: @abc.abstractmethod
...: def foo(self):
...: pass
...:
In [13]: class MyTable(Base, BaseAbstract):
...: __tablename__ = 'mytable'
...: id = Column(Integer, primary_key=True)
...:
In [14]: MyTable()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-1686a36a17c6> in <module>()
----> 1 MyTable()
TypeError: "Can't instantiate abstract class MyTable with abstract methods foo"
In [18]: class MyOtherTable(Base, BaseAbstract):
...: __tablename__ = 'myothertable'
...: id = Column(Integer, primary_key=True)
...: def foo(self):
...: return 'bar'
...:
In [19]: MyOtherTable()
Out[19]: <__main__.MyOtherTable at 0x7f01b4b592b0>
Run Code Online (Sandbox Code Playgroud)
不过,我不能保证。它可能包含许多惊喜。
| 归档时间: |
|
| 查看次数: |
630 次 |
| 最近记录: |