英文:
Type hint a SQLAlchemy 2 declarative model
问题
I create my SQLAlchemy models in the 2.0 way:
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "user_account"
id: Mapped[int] = mapped_column(primary_key=True)
I'm writing a function which does something to one of these models:
def drop_table(model):
model.__table__.drop()
如何在这里对model
进行类型提示,以便我的类型提示器:
- 知道
model.__table__
有哪些方法? - 接受
drop_table(User)
?
我天真地以为我可以这样做:
def drop_table(model: Base):
...
但这给了我以下错误:
"Type[DeclarativeAttributeIntercept]" is incompatible with "Type[Base]"
英文:
I create my SQLAlchemy models in the 2.0 way:
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "user_account"
id: Mapped[int] = mapped_column(primary_key=True)
I'm writing a function which does something to one of these models:
def drop_table(model):
model.__table__.drop()
How can I type hint model
here, such that my type hinter will:
- Know which methods
model.__table__
has got? - Accept
drop_table(User)
?
I naively assumed I could do:
def drop_table(model: Base):
...
but that gives me:
> "Type[DeclarativeAttributeIntercept]" is incompatible with "Type[Base]"
答案1
得分: 1
我目前还没有完美的答案,但这是我能做到的最好的:
```python
from sqlalchemy.orm import MappedClassProtocol
from sqlalchemy import Table
def drop_table(model: MappedClassProtocol):
table: Table = model.__table__ # type: ignore
model.__table__.drop()
drop_table(User) # 这个类型检查没问题
所以,MappedClassProtocol
允许函数接受一个ORM模型,但不幸的是 model.__table__
不是一个 Table
,所以我们必须加上 # type: ignore
。有人能改进这个吗?
<details>
<summary>英文:</summary>
I don't have the perfect answer so far, but here's the best I can do:
```python
from sqlalchemy.orm import MappedClassProtocol
from sqlalchemy import Table
def drop_table(model: MappedClassProtocol):
table: Table = model.__table__ # type: ignore
model.__table__.drop()
drop_table(User) # this type checks ok
So MappedClassProtocol
allows the function to accept an ORM model, but unfortunately model.__table__
doesn't appear as a Table
so we've got to do one # type: ignore
.
Can anyone improve on this?
答案2
得分: 0
与您正在做的非常相似,没有 `# type: ignore`,而是一个 `assert` 检查。
从搜索SQLAlchemy源代码来看,这似乎是它们在内部处理的方式 - 这是我想要分享的主要信息。所以我现在可能会暂时使用这个。
```python
def drop_table(model: MappedClassProtocol):
assert isinstance(model.__table__, Table)
model.__table__.drop()
这种类型检查是没问题的。但我想对于某些结构,您可能会得到一个 AssertionError
,这是mypy没有检测到的。
<details>
<summary>英文:</summary>
Pretty similar to what you're doing, without `# type: ignore` but rather an `assert` check.
From searching the SQLAlchemy source code, it looks like that's the way they do it internally - that's the main info I wanted to share. So I'm probably going to use this for now.
```python
def drop_table(model: MappedClassProtocol):
assert isinstance(model.__table__, Table)
model.__table__.drop()
Which type-checks fine. But I guess for some constructs you could get an AssertionError
that mypy hasn't detected.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论