Skip to main content
 首页 » 编程设计

python之flask SQLAlchemy | MySql之多个外键问题

2024年08月25日23haluo1

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 将获得空值。为什么?这样做的正确方法是什么?

请您参考如下方法:

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

外键只是一个数据库级别的约束,以确保您无法引用不存在的行(此外,它有助于 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,因为主键始终是唯一的。这使您的模型更容易:

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

您还可以删除 Devices 模型中的 role_permissions 列(顺便说一句,应该命名为 Device)。如果需要权限,直接从role中获取即可(如果平时需要,在外键上加上lazy=False,那么查询一个device会一直加入role表,避免额外查询)