Flask-SQLAlchemy 多态关联

Gof*_*tty 4 python postgresql sqlalchemy flask flask-sqlalchemy

我有两个主表,即角色用户,在用户上我将 3 个关联到表操作员教师学生

到目前为止,我是这样做的:

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    permissions = db.Column(db.Integer)
    users = db.relationship('User',
                            backref='role', lazy='dynamic')


class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), index=True)
    email = db.Column(db.String(64), unique=True, index=True)

    password_hash = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    __mapper_args__ = {
        'polymorphic_identity': 'users',
        'with_polymorphic': '*',
    }


class Operator(User):
    __tablename__ = 'operator'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))

    __mapper_args__ = {
        'polymorphic_identity': 'operator',
        'with_polymorphic': '*'
    }


class Teacher(User):
    __tablename__ = 'teacher'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    phone_number = db.Column(db.Integer)
    other_teacher_data = db.Column(db.String)

    __mapper_args__ = {
        'polymorphic_identity': 'teacher',
        'with_polymorphic': '*'
    }


class Student(User):
    __tablename__ = 'student'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    other_student_data = db.Column(db.String)

    __mapper_args__ = {
        'polymorphic_identity': 'student',
        'with_polymorphic': '*'
    }
Run Code Online (Sandbox Code Playgroud)

但我收到此错误消息:

尝试刷新作为集合“Role.users”成员的类型的项目。需要类型的对象或多态子类。如果 是 的子类,则配置映射器“Mapper|User|users”以多态方式加载此子类型,或设置enable_typechecks=False 以允许接受任何子类型进行刷新。

我尝试在角色表上的用户字段enable_typechecks=False上进行设置,然后收到以下错误消息:

psycopg2.errors.UniqueViolation)重复键值违反唯一约束“ix_users_email”详细信息:键(电子邮件)=(zidanecr7kaka2@gmail.com)已存在。[SQL: '插入用户(已确认、名字、姓氏、电子邮件、密码哈希、角色 ID、出生日期、地址、创建时间、更新时间)值 (%(已确认)s、%(名字)s、%(姓氏)s、%( email)s, %(password_hash)s, %(role_id)s, %(date_of_birth)s, %(address)s, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) 返回 users.id'] [参数: {'confirmed': False, 'first_name ': 'Tri', 'last_name': 'Nanda', '电子邮件': 'zidanecr7kaka2@gmail.com', 'password_hash': 'pbkdf2:sha1:1000$PtpuVYh4$b5bbb03939cf6ca9013308b62276889d35a8cc1b', 'role_id': 5、'出生日期':无,'地址':无}]

即使我尝试使用不同的数据,我也收到了该消息,但它仍然显示重复的键值。

请问,我的代码有什么问题..?或者任何类似情况的示例..?

Res*_*her 5

指出不同 :)

from app import db
from flask_login import UserMixin

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    permissions = db.Column(db.Integer)
    users = db.relationship('User',
                            backref='role', lazy='dynamic')


class User(UserMixin, db.Model): 
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    type = db.Column(db.String(50))
    name = db.Column(db.String(64), index=True)
    email = db.Column(db.String(64), unique=True, index=True)

    password_hash = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    __mapper_args__ = {
        'polymorphic_identity': 'users',
        'with_polymorphic': '*',
        "polymorphic_on": type
    }


class Operator(User):
    __tablename__ = 'operator'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))

    __mapper_args__ = {
        'polymorphic_identity': 'operator',
        'with_polymorphic': '*'
    }


class Teacher(User):
    __tablename__ = 'teacher'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    phone_number = db.Column(db.Integer)
    other_teacher_data = db.Column(db.String)

    __mapper_args__ = {
        'polymorphic_identity': 'teacher',
        'with_polymorphic': '*'
    }


class Student(User):  
    __tablename__ = 'student'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    other_student_data = db.Column(db.String)

    __mapper_args__ = {
        'polymorphic_identity': 'student',
        'with_polymorphic': '*'
    }
Run Code Online (Sandbox Code Playgroud)

这不是一个好的错误消息,但您错过了基类上的类型字段。它需要在某个地方存储子项的类型,否则如果您对基类和预期的多态性运行查询,它将必须搜索所有其他子表以匹配 id。看:

https://docs.sqlalchemy.org/en/13/orm/inheritance.html

上面,建立了一个附加的列类型来充当鉴别器,使用 mapper.polymorphic_on 参数进行配置。该列将存储一个值,该值指示行中表示的对象的类型。该列可以是任何数据类型,但字符串和整数是最常见的。

虽然多态鉴别器表达式并不是严格必要的,但如果需要多态加载,则需要它。在基表上建立一个简单列是实现此目的的最简单方法,但是非常复杂的继承映射甚至可以将 SQL 表达式(例如 CASE 语句)配置为多态鉴别器。

他们还在教程中建议您不要在子项中使用单独的 id 列,并将子项 id 列作为主键和外键返回到基数。

您可能需要删除“with_polymorphic”:“*”,因为它会预先加载所有子字段(效率低下)。在某些情况下,当您执行过滤器时,您可能需要此功能,但您可以在执行查询时将其打开:

https://docs.sqlalchemy.org/en/13/orm/inheritance_loading.html