如何将我自己的 Meta 类与 SQLAlchemy-Model 作为父类一起使用

Kıv*_*sel 7 python types sqlalchemy metaclass

我最近开始使用 Flask 作为我的后端框架。然而,最近我遇到了一个问题,我不知道如何解决。作为最后的手段,我想在这里尝试一下我的改变。如果您能帮助我,我将不胜感激。

所以,我有一个继承自 SQLAlchemy 的 db.Model 的类:

from flask_sqlalchemy import SQLAlchemy


db = SQLAlchemy()


class User(db.Model):
  ...

Run Code Online (Sandbox Code Playgroud)

我想创建自己的 Meta 类来自动向此类插入一些 Mixin:

class MyMetaClass(type):
  def __new__(meta, name, bases, class_dict):
    bases += (Mixin1, Mixin2, Mixin3)
    return type.__new__(meta, name, bases, class_dict)
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试将此 Meta 类与User类一起使用时:

class User(db.Model, metaclass=MyMetaClass):
   ...
Run Code Online (Sandbox Code Playgroud)

我有以下错误:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Run Code Online (Sandbox Code Playgroud)

有人知道如何解决这个问题吗?任何帮助,将不胜感激。

(注:我既不是 Flask 也不是 Meta 类的高手。所以如果我理解有误,请原谅我的理解不足)

Kıv*_*sel 3

最后我设法解决了我的问题。如果其他人遇到同样的问题,我在这里发布解决方案。

这是从SQLAlchemy 网站上截取的片段:


模型元类负责在定义模型子类时设置 SQLAlchemy 内部结构。Flask-SQLAlchemy 通过 mixins 添加了一些额外的行为;它的默认元类 DefaultMeta 继承了所有这些。

  • BindMetaMixin:bind_key从类中提取并应用于表。请参阅使用绑定的多个数据库。
  • NameMetaMixin:如果模型未指定表名但指定了主键,则会自动生成名称。

您可以通过定义自己的元类并自己创建声明性基础来添加自己的行为。确保仍然从您想要的 mixins 继承(或者只是从默认元类继承)。

如上所示,将声明性基类而不是简单模型基类传递给 base_class 将导致 Flask-SQLAlchemy 使用此基类,而不是使用默认元类构造基类。

from flask_sqlalchemy import SQLAlchemy
from flask_sqlalchemy.model import DefaultMeta, Model

class CustomMeta(DefaultMeta):
    def __init__(cls, name, bases, d):
        # custom class setup could go here

        # be sure to call super
        super(CustomMeta, cls).__init__(name, bases, d)

    # custom class-only methods could go here

db = SQLAlchemy(model_class=declarative_base(
    cls=Model, metaclass=CustomMeta, name='Model'))
Run Code Online (Sandbox Code Playgroud)

您还可以将所需的任何其他参数传递给 declarative_base() 以根据需要自定义基类。


除此之外,我最初的目的实际上是为我的模型添加一些额外的功能,这些功能继承自db.Model。实际上,您不需要使用元类来做到这一点。因此,对于这种情况,我们可以扩展db.Model类,如同一网页中所述。这是为每个模型提供一个整数主键或用于连接表继承的外键的示例:

from flask_sqlalchemy import Model, SQLAlchemy
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declared_attr, has_inherited_table

class IdModel(Model):
    @declared_attr
    def id(cls):
        for base in cls.__mro__[1:-1]:
            if getattr(base, '__table__', None) is not None:
                type = sa.ForeignKey(base.id)
                break
        else:
            type = sa.Integer

        return sa.Column(type, primary_key=True)

db = SQLAlchemy(model_class=IdModel)

class User(db.Model):
    name = db.Column(db.String)

class Employee(User):
    title = db.Column(db.String)
Run Code Online (Sandbox Code Playgroud)