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值。为什么?什么是正确的方法?
答案 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
添加到外键,然后查询设备将始终加入角色表以避免额外查询)