用SQLAlchemy和mypy定义的模型在初始化期间需要一个关系参数。

huangapple go评论96阅读模式
英文:

Model defined with SQLAlchemy and mypy requires a relationship parameter during initialization

问题

以下是代码的翻译部分,不包括代码本身:

  1. 我定义了如下模型
  2. class Base(MappedAsDataclass, DeclarativeBase):
  3. """子类将被转换为数据类"""
  4. class Prompt(Base):
  5. __tablename__ = "Prompt"
  6. id = mapped_column(
  7. "id",
  8. UUID(as_uuid=True),
  9. primary_key=True,
  10. index=True,
  11. server_default=sa.text("gen_random_uuid()"),
  12. )
  13. created_at = mapped_column(
  14. "created_at", DateTime(timezone=True), server_default=func.now(), nullable=False
  15. )
  16. text: Mapped[str] = mapped_column(Text)
  17. display_name: Mapped[str] = mapped_column("display_name", String)
  18. # 一对多关系
  19. owner_id: Mapped[uuid.UUID] = mapped_column(
  20. "owner_id",
  21. UUID(as_uuid=True),
  22. ForeignKey("User.id"),
  23. )
  24. owner: Mapped[User] = relationship("User", back_populates="prompts")
  25. # 多对多关系
  26. transcripts: Mapped[List[Transcript]] = relationship(
  27. "Transcript",
  28. secondary=transcript_prompt_association,
  29. back_populates="prompts",
  30. )
  31. deleted: Mapped[bool] = mapped_column("deleted", Boolean, default=False)

当我想要创建模型的实例时:

  1. db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)

我收到以下错误信息:

  1. 在调用“Prompt”时缺少位置参数“owner”和“transcripts [call-arg]mypy

我应该如何修复它?

我已经尝试过:

  1. owner: Optional[Mapped[User]] = relationship("User", back_populates="prompts")

=> 同样的错误。

我认为mypy应该自动理解在初始化时不需要关系字段。

编辑:

我的mypy.ini

  1. [mypy]
  2. python_version = 3.11
  3. plugins = pydantic.mypy,sqlalchemy.ext.mypy.plugin
  4. ignore_missing_imports = True
  5. disallow_untyped_defs = True
  6. exclude = (?x)(
  7. alembic # 文件名为“one.py”
  8. )
英文:

I have a model defined as following:

  1. class Base(MappedAsDataclass, DeclarativeBase):
  2. """subclasses will be converted to dataclasses"""
  3. class Prompt(Base):
  4. __tablename__ = "Prompt"
  5. id = mapped_column(
  6. "id",
  7. UUID(as_uuid=True),
  8. primary_key=True,
  9. index=True,
  10. server_default=sa.text("gen_random_uuid()"),
  11. )
  12. created_at = mapped_column(
  13. "created_at", DateTime(timezone=True), server_default=func.now(), nullable=False
  14. )
  15. text: Mapped[str] = mapped_column(Text)
  16. display_name: Mapped[str] = mapped_column("display_name", String)
  17. # many to one relationship
  18. owner_id: Mapped[uuid.UUID] = mapped_column(
  19. "owner_id",
  20. UUID(as_uuid=True),
  21. ForeignKey("User.id"),
  22. )
  23. owner: Mapped[User] = relationship("User", back_populates="prompts")
  24. # many-to-many relationship
  25. transcripts: Mapped[List[Transcript]] = relationship(
  26. "Transcript",
  27. secondary=transcript_prompt_association,
  28. back_populates="prompts",
  29. )
  30. deleted: Mapped[bool] = mapped_column("deleted", Boolean, default=False)

When I want to create an instance of the model:

  1. db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)

I receive the following error:

  1. Missing positional arguments "owner", "transcripts" in call to "Prompt" [call-arg]mypy

How can I fix it?

I already tried to:

  1. 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

  1. [mypy]
  2. python_version = 3.11
  3. plugins = pydantic.mypy,sqlalchemy.ext.mypy.plugin
  4. ignore_missing_imports = True
  5. disallow_untyped_defs = True
  6. exclude = (?x)(
  7. alembic # files named "one.py"
  8. )

答案1

得分: 1

由于您的Base扩展了MappedAsDataClass,所以您在这里使用了一个Python数据类。错误消息“缺少位置参数“owner”…”来自于生成的初始化方法中,“owner”是一个必需的字段(mypy只是提醒您这一点)。

您可以通过添加init=False来将owner从必需字段中排除:

  1. owner: Mapped[User] = relationship("User", back_populates="prompts", init=False)

或者,您可以为其提供默认值None

  1. owner: Mapped[User] = relationship("User", back_populates="prompts", default=None)

然而,如果您给它一个默认值为None,并且仍然使用之前的方法初始化实例:

  1. db_prompt = models.Prompt(text=text, display_name=display_name, owner_id=user_id)

owner字段将由于数据类生成初始化方法的方式而覆盖owner_idNone

因此,您可以选择:

  1. 不要使用数据类为此类自动生成初始化方法:
  1. class Prompt(Base, init=False):
  1. 或者,添加一个后初始化方法,如果它是None,则删除该属性,以便您的owner_id不会被空值覆盖:
  1. def __post_init__(self):
  2. if (self.owner is None):
  3. 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:

  1. owner: Mapped[User] = relationship("User", back_populates="prompts", init=False)

Alternatively, you can give it a default value of None:

  1. 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:

  1. 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:

  1. Don't use dataclass to automatically generate the init method for this class:
  1. class Prompt(Base, init=False):
  1. Or, add a post init method and remove the the attribute if it's None so
    your owner_id does not get overwritten by a null value:
  1. def __post_init__(self):
  2. if (self.owner is None):
  3. 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....

huangapple
  • 本文由 发表于 2023年6月2日 08:13:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76386442.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定