Flask sqlalchemy 多对多插入数据
Posted
技术标签:
【中文标题】Flask sqlalchemy 多对多插入数据【英文标题】:Flask sqlalchemy many-to-many insert data 【发布时间】:2014-10-29 08:34:37 【问题描述】:我试图在 Flask-SQLAlchemy 中建立多对多关系,但似乎我不知道如何填写 “多对多标识符数据库”。你能帮我理解我做错了什么以及它应该是什么样子吗?
class User(db.Model):
__tablename__ = 'users'
user_id = db.Column(db.Integer, primary_key=True)
user_fistName = db.Column(db.String(64))
user_lastName = db.Column(db.String(64))
user_email = db.Column(db.String(128), unique=True)
class Class(db.Model):
__tablename__ = 'classes'
class_id = db.Column(db.Integer, primary_key=True)
class_name = db.Column(db.String(128), unique=True)
然后是我的标识符数据库:
student_identifier = db.Table('student_identifier',
db.Column('class_id', db.Integer, db.ForeignKey('classes.class_id')),
db.Column('user_id', db.Integer, db.ForeignKey('users.user_id'))
)
到目前为止,当我尝试将数据插入数据库时,它看起来像这样。
# User
user1 = User(
user_fistName='John',
user_lastName='Doe',
user_email='john@doe.es')
user2 = User(
user_fistName='Jack',
user_lastName='Doe',
user_email='jack@doe.es')
user3 = User(
user_fistName='Jane',
user_lastName='Doe',
user_email='jane@doe.es')
db.session.add_all([user1, user2, user3])
db.session.commit()
# Class
cl1 = Class(class_name='0A')
cl2 = Class(class_name='0B')
cl3 = Class(class_name='0C')
cl4 = Class(class_name='Math')
cl5 = Class(class_name='Spanish')
db.session.add_all([cl1, cl2, cl3, cl4, cl5])
db.session.commit()
现在我的问题是,由于我真的无法创建“student_identifier”对象,我该如何添加到多对多数据库?如果可以的话,它可能看起来像这样:
# Student Identifier
sti1 = StiClass(class_id=cl1.class_id, class_name=user1.user_id)
sti2 = StiClass(class_id=cl3.class_id, class_name=user1.user_id)
sti3 = StiClass(class_id=cl4.class_id, class_name=user1.user_id)
sti4 = StiClass(class_id=cl2.class_id, class_name=user2.user_id)
db.session.add_all([sti1, sti2, sti3, sti4])
db.session.commit()
我应该如何使用 ORM 插入多对多表?
【问题讨论】:
【参考方案1】:您不需要直接向关联表中添加任何内容,SQLAlchemy 会这样做。这或多或少来自SQLAlchemy documentations:
association_table = db.Table('association', db.Model.metadata,
db.Column('left_id', db.Integer, db.ForeignKey('left.id')),
db.Column('right_id', db.Integer, db.ForeignKey('right.id'))
)
class Parent(db.Model):
__tablename__ = 'left'
id = db.Column(db.Integer, primary_key=True)
children = db.relationship("Child",
secondary=association_table)
class Child(db.Model):
__tablename__ = 'right'
id = db.Column(db.Integer, primary_key=True)
p = Parent()
c = Child()
p.children.append(c)
db.session.add(p)
db.session.commit()
因此您的示例将是这样的:
student_identifier = db.Table('student_identifier',
db.Column('class_id', db.Integer, db.ForeignKey('classes.class_id')),
db.Column('user_id', db.Integer, db.ForeignKey('students.user_id'))
)
class Student(db.Model):
__tablename__ = 'students'
user_id = db.Column(db.Integer, primary_key=True)
user_fistName = db.Column(db.String(64))
user_lastName = db.Column(db.String(64))
user_email = db.Column(db.String(128), unique=True)
class Class(db.Model):
__tablename__ = 'classes'
class_id = db.Column(db.Integer, primary_key=True)
class_name = db.Column(db.String(128), unique=True)
students = db.relationship("Student",
secondary=student_identifier)
s = Student()
c = Class()
c.students.append(s)
db.session.add(c)
db.session.commit()
【讨论】:
假设我的学生已经存在于一个表中。如何将它们附加到一个班级,而不必每次都查询每个学生的全部数据(仅使用外键)? @axwell,如果您经常需要学生上课(即检查更新时),您可以像这样调整与 lazy='subquery' 的关系:students = db.relationship("Student", secondary=student_identifier, lazy='subquery', backref=db.backref('classes', lazy=True))
@axwell 如果学生已经存在,您也可以这样插入:session.execute( student_identifier.insert(), params="class_id": class_id, "user_id": user_id, )
【参考方案2】:
首先,student_identifier
被定义为 SQLAlchemy 反射表而不是数据库。
通常,如果您正确设置了模型和反射表对象之间的所有关系,则只需处理相关模型(通过将模型对象附加到关系 InstrumentList 中)即可将数据插入反射表中,例如,上面提供的答案@mehdi-sadeghi。
但是,如果您不想设置关系,确实有一种方法可以直接插入到反射表中。例如:
statement = student_identifier.insert().values(class_id=cl1.id, user_id=sti1.id)
db.session.execute(statement)
db.session.commit()
之后应该可以看到student_identifier
反射表中插入了多对多关系行。不要忘记在执行每个 SQL 语句后提交,因为它是在事务中完成的。
希望通过另一种方法对您有所帮助。
【讨论】:
如何导入这个反射表或关联表? @jibinmathew 就像使用类和其他符号一样。 @jibinmathew 我在导入关联表时也遇到了问题,所以我在本地导入表,就在上面我调用它的地方。 @GofyandKitty 这可能是代码库中循环依赖/导入的指标,因此您需要使用本地导入(提供命名空间)才能使其工作。 非常感谢分享这个解决方案。你真的救了我【参考方案3】:要扩展牛鳃答案,您还可以使用 extend
一次添加多个条目:
class_ = db.session.query(Class).first()
new_students = db.session.query(Student).all()
class_.students.extend(new_students)
db.session.add(class_)
db.session.commit()
【讨论】:
以上是关于Flask sqlalchemy 多对多插入数据的主要内容,如果未能解决你的问题,请参考以下文章
Flask-SQLAlchemy 配置,处理对象-关系,一对多,多对多
深入浅出Flask(50):flask_sqlalchemy的创建多对多的关系表