【问题标题】:Flask sqlalchemy many-to-many insert dataFlask sqlalchemy 多对多插入数据
【发布时间】: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 插入多对多表?

【问题讨论】:

    标签: python flask sqlalchemy flask-sqlalchemy


    【解决方案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()
    

    【讨论】:

      猜你喜欢
      • 2017-05-04
      • 2020-03-23
      • 1970-01-01
      • 1970-01-01
      • 2014-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-05
      相关资源
      最近更新 更多