英文:
Model defined with SQLAlchemy and mypy requires a relationship parameter during initialization
问题
以下是代码的翻译部分,不包括代码本身:
我定义了如下模型:
class Base(MappedAsDataclass, DeclarativeBase):
"""子类将被转换为数据类"""
class Prompt(Base):
__tablename__ = "Prompt"
id = mapped_column(
"id",
UUID(as_uuid=True),
primary_key=True,
index=True,
server_default=sa.text("gen_random_uuid()"),
)
created_at = mapped_column(
"created_at", DateTime(timezone=True), server_default=func.now(), nullable=False
)
text: Mapped[str] = mapped_column(Text)
display_name: Mapped[str] = mapped_column("display_name", String)
# 一对多关系
owner_id: Mapped[uuid.UUID] = mapped_column(
"owner_id",
UUID(as_uuid=True),
ForeignKey("User.id"),
)
owner: Mapped[User] = relationship("User", back_populates="prompts")
# 多对多关系
transcripts: Mapped[List[Transcript]] = relationship(
"Transcript",
secondary=transcript_prompt_association,
back_populates="prompts",
)
deleted: Mapped[bool] = mapped_column("deleted", Boolean, default=False)
当我想要创建模型的实例时:
db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)
我收到以下错误信息:
在调用“Prompt”时缺少位置参数“owner”和“transcripts” [call-arg]mypy
我应该如何修复它?
我已经尝试过:
owner: Optional[Mapped[User]] = relationship("User", back_populates="prompts")
=> 同样的错误。
我认为mypy应该自动理解在初始化时不需要关系字段。
编辑:
我的mypy.ini
[mypy]
python_version = 3.11
plugins = pydantic.mypy,sqlalchemy.ext.mypy.plugin
ignore_missing_imports = True
disallow_untyped_defs = True
exclude = (?x)(
alembic # 文件名为“one.py”
)
英文:
I have a model defined as following:
class Base(MappedAsDataclass, DeclarativeBase):
"""subclasses will be converted to dataclasses"""
class Prompt(Base):
__tablename__ = "Prompt"
id = mapped_column(
"id",
UUID(as_uuid=True),
primary_key=True,
index=True,
server_default=sa.text("gen_random_uuid()"),
)
created_at = mapped_column(
"created_at", DateTime(timezone=True), server_default=func.now(), nullable=False
)
text: Mapped[str] = mapped_column(Text)
display_name: Mapped[str] = mapped_column("display_name", String)
# many to one relationship
owner_id: Mapped[uuid.UUID] = mapped_column(
"owner_id",
UUID(as_uuid=True),
ForeignKey("User.id"),
)
owner: Mapped[User] = relationship("User", back_populates="prompts")
# many-to-many relationship
transcripts: Mapped[List[Transcript]] = relationship(
"Transcript",
secondary=transcript_prompt_association,
back_populates="prompts",
)
deleted: Mapped[bool] = mapped_column("deleted", Boolean, default=False)
When I want to create an instance of the model:
db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)
I receive the following error:
Missing positional arguments "owner", "transcripts" in call to "Prompt" [call-arg]mypy
How can I fix it?
I already tried to:
owner: Optional[Mapped[User]] = relationship("User", back_populates="prompts")
=> Same error.
I thought mypy understands automatically that a relationship field is not required during init.
EDIT:
My mypy.ini
[mypy]
python_version = 3.11
plugins = pydantic.mypy,sqlalchemy.ext.mypy.plugin
ignore_missing_imports = True
disallow_untyped_defs = True
exclude = (?x)(
alembic # files named "one.py"
)
答案1
得分: 1
由于您的Base
扩展了MappedAsDataClass
,所以您在这里使用了一个Python数据类。错误消息“缺少位置参数“owner”…”来自于生成的初始化方法中,“owner”是一个必需的字段(mypy只是提醒您这一点)。
您可以通过添加init=False
来将owner从必需字段中排除:
owner: Mapped[User] = relationship("User", back_populates="prompts", init=False)
或者,您可以为其提供默认值None
:
owner: Mapped[User] = relationship("User", back_populates="prompts", default=None)
然而,如果您给它一个默认值为None
,并且仍然使用之前的方法初始化实例:
db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)
owner
字段将由于数据类生成初始化方法的方式而覆盖owner_id
为None
。
因此,您可以选择:
- 不要使用数据类为此类自动生成初始化方法:
class Prompt(Base, init=False):
- 或者,添加一个后初始化方法,如果它是
None
,则删除该属性,以便您的owner_id
不会被空值覆盖:
def __post_init__(self):
if (self.owner is None):
delattr(self, "owner")
这是一种有点巧妙的方法,不建议使用。在您进行修改后,您可以使用Prompt(owner_id=user_id, ...
或Prompt(owner=user...
来实例化一个实例。
英文:
Since your Base
extends MappedAsDataClass
, you are using a Python dataclass
here. The error message "Missing positional arguments "owner", ..." comes from
the fact that in the generated init method, "owner" is a required field (mypy is
just reminding you of that fact).
You can exclude owner from the required field by adding init=False
:
owner: Mapped[User] = relationship("User", back_populates="prompts", init=False)
Alternatively, you can give it a default value of None
:
owner: Mapped[User] = relationship("User", back_populates="prompts", default=None)
However, if you give it a default value of None
and still use your previous
method to initialize the instance:
db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)
The owner
field will overwrite owner_id
with None due to how a dataclass
generates the init method.
So, you can either:
- Don't use dataclass to automatically generate the init method for this class:
class Prompt(Base, init=False):
- Or, add a post init method and remove the the attribute if it's
None
so
yourowner_id
does not get overwritten by a null value:
def __post_init__(self):
if (self.owner is None):
delattr(self, "owner")
This is kind of a hack and is not recommended. After you made the modification,
you can instantiate an instance with either Prompt(owner_id=user_id, ...
or
Prompt(owner=user...
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论