我想为我的SQLAlchemy基类使用类型,但似乎找不到类型定义。
例如:
from sqlalchemy.types import BigInteger
from sqlalchemy.schema import Column, Index
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id_user = Column(
BigInteger, primary_key=True, autoincrement=True, nullable=False, index=True
)
username = Column(String, unique=True, index=True)现在,当引用这个User类时,我不知道该使用哪种类型。此外,如果我想拥有一个包含table_name :模型映射的字典,如下所示:
from typing import Any, Dict
table_model_map: Dict[str, Any] = {
"users": User,
"another_table": AnotherTableModel,
}我该如何定义这个字典的类型?
非常感谢你帮我理解这一点!
发布于 2019-10-17 12:06:41
Base是所有模型(也是类型)都继承的类型,因此
Dict[str, Base]发布于 2021-06-03 16:25:37
Ilja是正确的,因为如果你所有的模型类都是Base的子类,这是一个适合输入提示你的字典的选项。
但是,如果您想在创建之前键入将Base作为参数接收的提示内容,即如下所示:
class DatabaseJanitor:
def __init__(self, base: WhatTypeHere?, engine):
self._base = base
self._engine = engine
def create_metadata(self):
self._base.metadata.create_all(self._engine)这就有点棘手了。我做了一些挖掘,这是我为sqlalchemy-1.4.17找到的。
在sqlalchemy/orm/decl_api.py中可以看到以下内容
class DeclarativeMeta(type):
def __init__(cls, classname, bases, dict_, **kw):
...
def declarative_base(
...
metaclass=DeclarativeMeta,
):
...
return registry(
_bind=bind,
metadata=metadata,
class_registry=class_registry,
constructor=constructor,
).generate_base(
mapper=mapper,
cls=cls,
name=name,
metaclass=metaclass,
)
class registry(object):
...
def generate_base(
...
metaclass=DeclarativeMeta,
):
metadata = self.metadata
bases = not isinstance(cls, tuple) and (cls,) or cls
class_dict = dict(registry=self, metadata=metadata)
if isinstance(cls, type):
class_dict["__doc__"] = cls.__doc__
if self.constructor:
class_dict["__init__"] = self.constructor
class_dict["__abstract__"] = True
if mapper:
class_dict["__mapper_cls__"] = mapper
return metaclass(name, bases, class_dict)因此,declarative_base将返回传入的metaclass关键字参数的一个实例。因此,Base = declarative_base(metaclass=MyNewMetaclass)将导致type(Base) == MyNewMetaclass。
此外,正如您在registry.generate_base中看到的,元类的新实例(如metadata)的所有属性都包含在class_dict中。这些属性在创建期间作为属性隐式添加到实例中,因此它们在类型提示期间不可用。
(旁注:我做了一些研究,似乎因为DeclarativeMeta是type的子类,所以type.__new__被隐式调用,然后将class_dict字典中的值作为属性添加到DeclarativeMeta的实例中。我将在本答案的末尾链接一些资源以供进一步阅读。)
所以,即使你像这样输入hint你的函数:
class DatabaseJanitor:
def __init__(self, base: DeclarativeMeta, engine):
self._base = base
self._engine = engine
def create_metadata(self):
self._base.metadata.create_all(self._engine)在create_metadata中,您的类型提示将警告Unresolved attribute reference 'metadata' for class 'DeclarativeMeta'。
所以没有一个很好的方法来正确地输入提示declarative_base。我的方法是暂时将其添加到文档字符串中。
希望这对任何未来的读者都有帮助!:)
下面是一些关于类型/元类的进一步阅读:
https://stackoverflow.com/questions/58325495
复制相似问题