python 将SQlAlchemy模型标记为数据类

mv1qrgav  于 2023-01-04  发布在  Python
关注(0)|答案(1)|浏览(143)

我正试图弄清楚如何正确地使用类型提示与sqlalchemy。我有2个模型:

from sqlalchemy.orm import declarative_base

Base = declarative_base()
class Person(Base):
    __table__ = "persons"

    id: int = Column(Integer, primary_key=True)
    name: str = Column(String, nullable=False)
    age: str | None = Column(String)
    pets: list[Animal] = relationship(
        "Animal",
        back_populates="persons",
        lazy="selectin",
    )

class Animal(Base):
    __table__ = "animals"

    id: int = Column(Integer, primary_key=True)
    weight: float | None = Column(Float)
    max_age: int | None = Column(Integer)
    owner: Person = relationship(
        "Person",
        back_populates="animals",
        lazy="selectin",
    )

现在我想把它们都标记为dataclass,以拥有一个带typehints的__init__方法,现在我的问题是这是否是一个好主意,因为它们(Base和dataclass)都在下面做了一些"神奇的"事情,我想知道这是否会导致任何问题。
也许还有其他(更简单的)选择来实现这一点?

5lhxktic

5lhxktic1#

注册数据类时没有Base,它使用mapper_registry.mapped装饰器(docs):
这里是你的类作为声明性Map的数据类,但是我纠正了你写的关系。

from __future__ import annotations

from dataclasses import dataclass, field

from sqlalchemy import Column, Float, ForeignKey, Integer, String
from sqlalchemy.orm import registry, relationship

mapper_registry = registry()

@mapper_registry.mapped
@dataclass
class Person:
    __tablename__ = "persons"  # NOTE: __tablename__ not __table
    __sa_dataclass_metadata_key__ = "sa"
    id: int = field(init=False, metadata={"sa": Column(Integer, primary_key=True)})
    name: str = field(init=False, metadata={"sa": Column(String, nullable=False)})
    age: str | None = field(init=False, metadata={"sa": Column(String)})
    pets: list[Animal] = field(
        default_factory=list,
        metadata={
            "sa": relationship(
                "Animal",
                back_populates="owner",
                lazy="selectin",
            )
        },
    )

@mapper_registry.mapped
@dataclass
class Animal:
    __tablename__ = "animals"
    __sa_dataclass_metadata_key__ = "sa"
    id: int = field(init=False, metadata={"sa": Column(Integer, primary_key=True)})
    weight: float | None = field(init=False, metadata={"sa": Column(Float)})
    max_age: int | None = field(init=False, metadata={"sa": Column(Integer)})
    owner_id: id = field(init=False, metadata={"sa": Column(ForeignKey("persons.id"))})
    owner: Person = field(
        init=False,
        metadata={
            "sa": relationship(
                "Person",
                back_populates="pets",
                lazy="selectin",
            )
        },
    )

相关问题