代码之家  ›  专栏  ›  技术社区  ›  Plasma

sqlalchemy:子类模型db entry获取其他子类模型的属性

  •  0
  • Plasma  · 技术社区  · 7 年前

    我在一个flask应用程序中遇到了sqlalchemy问题,其中我有两个模型 Instructor Student 同一模型的子类 User . 当我创建一个 学生 对象,它列在数据库中 用户 属性应该是 教练 . 以下是我的(简化)课程:

    class User(db.Model):
        __tablename__ = "user"
        discriminator = db.Column("type", db.String(50))  # Student or Instructor
        __mapper_args__ = {"polymorphic_on": discriminator}
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50)) 
    
    class Instructor(User):
        __mapper_args__ = {"polymorphic_identity": "instructor"}
        reputation = db.Column(db.Integer, default=1)
        approved_for_teaching = db.Column(db.Boolean, default=False)
    
    class Student(User):
        __mapper_args__ = {"polymorphic_identity": "student"}
        lessons_taken = db.Column(db.Integer, default=0)
    

    我在创造一个 学生 这样地:

    new_student = Student(name=user_name)
    db.session.add(new_student)
    db.session.commit()
    

    但是当检查数据库中的对象时,学生从 教练 模型,即 reputation (值为1)和 approved_for_teaching (值为false)。我在这里做错了什么,还是这是预期的行为?我能理解这些列是否必须出现,因为它们共享同一个表( 用户 )在数据库中,但是我希望值为空或其他值。谢谢!

    1 回复  |  直到 7 年前
        1
  •  1
  •   Ilja Everilä    7 年前

    这是预期的行为,因为你在使用 single table inheritance :

    单表继承表示单个表中所有子类的所有属性。具有该类特有属性的特定子类将在表中的列中持久化这些属性,如果行引用其他类型的对象,则这些列将为空。

    尽管文档提到将属于其他类的列保留为空,但是在插入到 user 表,它是继承自 User ,即使它们不是特定子类列的一部分。一 context sensitive default function 或许可以用来避免这种情况,例如:

    def polymorphic_default(discriminator, identity, value):
        def default(context):
            # This should be replaced with context.get_current_parameters() in 1.2 and above
            if context.current_parameters[discriminator.name] == identity:
                return value
        return default
    
    ...
    
    class Instructor(User):
        __mapper_args__ = {"polymorphic_identity": "instructor"}
        reputation = db.Column(
            db.Integer, default=polymorphic_default(User.discriminator, 'instructor', 1))
        approved_for_teaching = db.Column(
            db.Boolean, default=polymorphic_default(User.discriminator, 'instructor', False))
    

    但这似乎是为了避免一个相当小的问题而做的大量工作。