从抽象类异常继承继承SQLAlchemy类时:元类冲突:派生类的元类必须为 [英] When inheriting SQLAlchemy class from abstract class exception thrown: metaclass conflict: the metaclass of a derived class must be
问题描述
以下代码是带有一个简单表的SqlAlchemy ORM的非常简单的实现。 Mytable类尝试从BaseAbstract继承。
The following code is a very simple implementation of a SqlAlchemy ORM with one simple table. The Mytable class tries to inherit from BaseAbstract.
代码抛出以下异常:
消息:元类冲突:派生类的元类必须是其所有基元元类的
a(非严格)子类
Message: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
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)
如果将类声明行更改为
类Mytable(Base):
class Mytable(Base):
代码可以正常工作。同样,如果将 BaseAbstract(ABC):
更改为 BaseAbstract(object):
类,代码将再次正常运行。
如何从SQLAlchemy中的抽象类继承?
the code will work fine. Also if you change class BaseAbstract(ABC):
to class BaseAbstract(object):
the code will again work fine.
How do I inherit from an abstract class in SQLAlchemy?
推荐答案
混合元类并不容易,您应该避免这种情况。 SQLAlchemy提供了一种处理抽象基类的方法或扩大基础,另一方面,您尝试做的事情看起来很像 mixin 。
Mixing metaclasses is not easy and you should avoid it. SQLAlchemy offers a way to handle abstract base classes or augmenting the base, and on the other hand what you're trying to do looks a lot like a mixin.
您可以指示SQLAlchemy跳过为一个表创建一个表和一个映射器使用 __ abstract __
:
You can instruct SQLAlchemy to skip creating a table and a mapper for a class using __abstract__
:
Base = declarative_base()
class BaseAbstract(Base):
"""description of class"""
__abstract__ = True
class Mytable(BaseAbstract):
...
您也可以增强 Base
类:
class BaseAbstract:
"""description of class"""
Base = declarative_base(cls=BaseAbstract)
class Mytable(Base):
...
但在我看来,最简单的解决方案是完全放弃使用抽象基础,并将其视为 mixin ,就像您已经做过的那样:
But in my opinion the easiest solution is to forego using an "abstract base" altogether and think of it as a mixin, as you had done already in a way:
class CommonMixin:
"""description of class"""
Base = declarative_base()
class Mytable(CommonMixin, Base):
...
但是,如果您坚持使用实际的 abc.ABC
抽象基类,将您的模型类注册为虚拟子类:
But if you insist on using an actual abc.ABC
abstract base class, register your model classes as virtual subclasses:
class BaseAbstract(ABC):
"""description of class"""
Base = declarative_base()
@BaseAbstract.register
class Mytable(Base):
...
缺点是 @ abc.abstractmethod
实例化虚拟子类时,不检查装饰方法。
The downside is that @abc.abstractmethod
decorated methods are not checked upon instantiating virtual subclasses.
如果上述方法不能满足您的需要,并且您想使用 ABC
要检查是否已实现必需的方法,可以尝试按照指示的操作进行操作,并创建一个新的元类,该元类是 DeclarativeMeta
和 ABCMeta
:
If the above do not fulfill your needs and you want to use ABC
for checking that required methods are implemented, you could try and do as the exception instructed and create a new metaclass that is the combination of DeclarativeMeta
and 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>
不过,我不能为此提供担保。它可能包含许多惊喜。
I cannot vouch for this, though. It might contain more than a few surprises.
这篇关于从抽象类异常继承继承SQLAlchemy类时:元类冲突:派生类的元类必须为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!