Flask-SQLAlchemy多态关联

时间:2019-07-12 04:03:22

标签: python postgresql flask sqlalchemy flask-sqlalchemy

我有两个主表,分别是角色 users ,在 users 上,我将3个表关联到 operator strong>,老师学生

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

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': '*'
    }

但是我收到此错误消息:

  

尝试刷新类型为集合成员的项目   “角色用户”。预期类型的​​对象或的多态子类   这种类型。如果是的子类,则配置映射器“ Mapper | User | users”   以多态加载此子类型,或设置enable_typechecks = False   以便允许接受任何子类型进行冲洗。

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

  

psycopg2.errors.UniqueViolation)重复键值违反唯一   约束“ ix_users_email”详细信息:键   (电子邮件)=(zidanecr7kaka2@gmail.com)已存在。 [SQL:'INSERT INTO   用户(已确认,名字,姓氏,电子邮件,密码哈希,   角色编号,出生日期,地址,created_at,updated_at)VALUES   (%(已确认)s,%(名字)s,%(姓氏)s,%(电子邮件)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','email':'zidanecr7kaka2@gmail.com','password_hash':   'pbkdf2:sha1:1000 $ PtpuVYh4 $ b5bbb03939cf6ca9013308b62276889d35a8cc1b',   'role_id':5,'date_of_birth':无,'address':无}}]

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

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

1 个答案:

答案 0 :(得分:2)

发现差异:)

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': '*'
    }

这不是一个好的错误消息,但是您错过了基类的type字段。它需要在某个地方存储子类型,否则,如果您对基类和期望的多态性进行查询,则必须搜索所有其他子表以匹配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