Flask SQL-Alchemy | MySql - 多个外键问题

时间:2015-10-16 22:14:42

标签: python sqlalchemy flask-sqlalchemy

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    default = db.Column(db.Boolean, default=False, index=True)
    permissions = db.Column(db.Integer)


class Devices(db.Model):
    __tablename__ = 'devices'
    id = db.Column(db.Integer, primary_key=True)
    purpose = db.Column('purpose', db.String(64))
    type = db.Column('type', db.String(64))
    name = db.Column('name', db.String(64))
    channel = db.Column('channel', db.Integer)
    role_id = db.Column('role_id', db.Integer)
    role_permissions = db.Column('role_permissions', db.Integer)
    role = db.ForeignKeyConstraint(['role_id', 'role_permissions'], ['roles.id', 'roles.permissions'])

然后我希望这可行:

dev = Devices(purpose="lights",type="tcp",name="zeus",channel=8)
role = Role.query.first()
dev.role = role
db.session.add(dev)
db.session.commit()

但是一旦持久化,role_id和role_permissions将获得null值。为什么?什么是正确的方法?

1 个答案:

答案 0 :(得分:3)

除了外键之外,还需要定义一个关系。

外键只是一个数据库级约束,以确保您不能引用不存在的行(此外,它有助于SQLAlchemy设置关系,而无需另外指定两个表如何链接)。

您希望在模型中使用此功能:

class Devices(db.Model):
    __table_args__ = (db.ForeignKeyConstraint(['role_id', 'role_permissions'], ['roles.id', 'roles.permissions']),)
    # ...
    role = db.relationship('Role', backref=db.backref('devices'))

通过这样做,device.role = some_role将正确填充外键,此外,每个Role实例都有一个devices集合,可让您访问其关联的设备。

SQLAlchemy教程还有一个关于关系的部分: http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#building-a-relationship

你几乎可以遵循它; Flask-SQLAlchemy和普通的SQLalchemy并没有什么不同 - Flask-SQLAlchemy只是通过db对象可以访问很多东西,以避免明确地导入它们。

顺便说一下,由于Role.id是主键,因此您不需要在外键中包含role_permissions - 您不能拥有多个角色相同的ID key始终是唯一的。这使您的模型更加轻松:

class Devices(db.Model):
    # ...
    role_id = db.Column('role_id', db.Integer, db.ForeignKey('roles.id'))
    role = db.relationship('Role', backref=db.backref('devices'))

您还可以删除role_permissions模型中的Devices列(顺便说一句,该列应命名为Device)。如果您需要权限,只需从角色中获取权限(如果您通常需要它,请将lazy=False添加到外键,然后查询设备将始终加入角色表以避免额外查询)