从抽象类异常继承继承SQLAlchemy类时:元类冲突:派生类的元类必须为 [英] When inheriting SQLAlchemy class from abstract class exception thrown: metaclass conflict: the metaclass of a derived class must be

查看:191
本文介绍了从抽象类异常继承继承SQLAlchemy类时:元类冲突:派生类的元类必须为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码是带有一个简单表的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屋!

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