flask sqlalchemy 与抽象类的关系错误

问题描述 投票:0回答:1

我有一组彼此相关的类

与招聘主题一对多 与 RecruitTable 进行一对多的招聘,RecruitTable 是其他几个类的抽象超类

这是类定义:

from typing import Optional, List
import sqlalchemy as sa
import sqlalchemy.orm as so

from app import db


class Subject(db.Model):
    __tablename__ = 'subject'

    id: so.Mapped[Optional[int]]        = so.mapped_column(sa.Integer, primary_key=True)

    recruitments: so.WriteOnlyMapped[List['Recruitment']] = so.relationship(back_populates='subject')


class Recruitment(db.Model):
    __tablename__ = 'recruitment'

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)
    subject: so.Mapped['Subject']                           = so.relationship('Subject', back_populates='recruitments')
    evaluations: so.WriteOnlyMapped[List['RecruitTable']]   = so.relationship('RecruitTable', back_populates='recruitment', cascade="all, delete-orphan")

class RecruitTable(db.Model):

    __abstract__ = True

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)

    @so.declared_attr
    def id_recruitment(self) -> so.Mapped[int]:
        return so.mapped_column(sa.Integer, sa.ForeignKey("recruitment.id"), index=True, nullable=False)

    @so.declared_attr
    def recruitment(self) -> so.Mapped[Recruitment]:
        return so.relationship('Recruitment', back_populates='evaluations') )


class SubTable1(RecruitTable):

    col1: so.Mapped[Optional[str]] = so.mapped_column(sa.String(16))


class SubTable2(RecruitTable):

    col2: so.Mapped[Optional[str]] = so.mapped_column(sa.String(16))

这是我收到的错误

sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'Mapper[Recruitment(recruitment)]'. Original exception was: When initializing mapper Mapper[Recruitment(recruitment)], expression 'RecruitTable' failed to locate a name ('RecruitTable'). If this is a class name, consider adding this relationship() to the <class 'app.database.models.Recruitment'> class after both dependent classes have been defined.

flask-sqlalchemy relationship
1个回答
0
投票

您遇到的错误通常发生在 SQLAlchemy 尝试在所有依赖类完全定义之前映射关系时。具体来说,当关系引用映射器尚未处理的类时,可能会发生这种情况。这种情况经常发生在抽象基类及其子类中。

要解决此问题,您应该确保 SQLAlchemy 在尝试映射关系之前完全了解所有子类。这可以通过在处理关系定义之前导入子类来实现。您还可以使用 mapper_args 属性来帮助解决此问题。

这是包含这些注意事项的更新代码:

from typing import Optional, List
import sqlalchemy as sa
import sqlalchemy.orm as so

from app import db


class Subject(db.Model):
    __tablename__ = 'subject'

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)

    recruitments: so.WriteOnlyMapped[List['Recruitment']] = so.relationship(back_populates='subject')


class Recruitment(db.Model):
    __tablename__ = 'recruitment'

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)
    subject_id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, sa.ForeignKey('subject.id'), nullable=False)
    subject: so.Mapped['Subject'] = so.relationship('Subject', back_populates='recruitments')
    evaluations: so.WriteOnlyMapped[List['RecruitTable']] = so.relationship('RecruitTable', back_populates='recruitment', cascade="all, delete-orphan")


class RecruitTable(db.Model):

    __abstract__ = True

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)

    @so.declared_attr
    def id_recruitment(cls) -> so.Mapped[int]:
        return so.mapped_column(sa.Integer, sa.ForeignKey("recruitment.id"), index=True, nullable=False)

    @so.declared_attr
    def recruitment(cls) -> so.Mapped['Recruitment']:
        return so.relationship('Recruitment', back_populates='evaluations')


class SubTable1(RecruitTable):

    __tablename__ = 'sub_table_1'

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)
    col1: so.Mapped[Optional[str]] = so.mapped_column(sa.String(16))


class SubTable2(RecruitTable):

    __tablename__ = 'sub_table_2'

    id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, primary_key=True)
    col2: so.Mapped[Optional[str]] = so.mapped_column(sa.String(16))


# Ensure all tables are imported/known to SQLAlchemy before defining relationships
db.configure_mappers()

主要变化:

  1. 向 Recruitment 添加了 subject_id :这明确定义了将 Recruitment 链接到主题的外键列。显式定义外键通常是一个好习惯。
  2. __mapper_args__
    用于确保 SQLAlchemy 了解表的多态性质,但对于这个特定示例来说并不是绝对必要的。
  3. 调用 db.configure_mappers() 可确保在完成依赖于这些映射的任何其他操作之前完成所有映射器配置。这在处理抽象基类及其关系时特别有用。

通过确保 SQLAlchemy 在处理关系时具有所有必需的类定义,应该可以解决初始化错误。

© www.soinside.com 2019 - 2024. All rights reserved.