烧瓶多对多插入数据

我试图在 烧瓶-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 _ Identity”对象,那么如何向多对多数据库中添加数据呢?如果我可以的话,它可能看起来像这样:

# 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 表?

91065 次浏览

You don't need to add anything directly to your association table, SQLAlchemy will do that. This is more or less from 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()

Therefore your sample would be like this:

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()

First off, student_identifier is defined as a SQLAlchemy reflection table not a database.

Normally if you have all the relationship setup properly between models and reflection table objects, you will only need to deal with related models (by appending model objects into the relationship InstrumentList) in order to insert data into reflection tables, for instance, the answer @mehdi-sadeghi provided above.

However, there is indeed a way to insert directly into reflection tables if you don't want to setup the relationship. For example:

statement = student_identifier.insert().values(class_id=cl1.id, user_id=sti1.id)
db.session.execute(statement)
db.session.commit()

After that, you should be able to see that a many-to-many relationship row is inserted into the student_identifier reflection table. Don't forget to commit after you execute each SQL statement as it's done in a transaction.

Hope that helps you with an alternative approach.

To extend cowgills answer, you can also add multiple entries at once using 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()

I had this on my models

show = db.Table('Show',
db.Column('artist_id', db.Integer, db.ForeignKey('artists.id'), primary_key = True),
db.Column('venue_id', db.Integer, db.ForeignKey('venues.id'), primary_key = True),
db.Column('start_time',db.DateTime, nullable = False )
)
class Venue(db.Model):
__tablename__ = 'venues'


id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
city = db.Column(db.String(120))
state = db.Column(db.String(120))
address = db.Column(db.String(120))
phone = db.Column(db.String(120))
facebook_link = db.Column(db.String(120))
image_link = db.Column(db.String(500))
genres = db.Column(db.String())
website_link = db.Column(db.String(120))
seeking_talent = db.Column(db.Boolean, nullable = False, default= False)
seeking_description = db.Column(db.String())
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    

def __repr__(self):
return f'<Venue ID: {self.id}, Name: {self.name}>'

class Artist(db.Model):
__tablename__ = 'artists'


id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
city = db.Column(db.String(120))
state = db.Column(db.String(120))
phone = db.Column(db.String(120))
genres = db.Column(db.String())
facebook_link = db.Column(db.String(120))
image_link = db.Column(db.String(500))
website_link = db.Column(db.String(120))
seeking_venue = db.Column(db.Boolean, nullable = False, default= False)
seeking_description = db.Column(db.String())
venues = db.relationship('Venue', secondary = show, backref = db.backref('artists', lazy = True))
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)


def __repr__(self):
return f'<Artist ID: {self.id}, Name: {self.name}>'

And I performed the insertion as follows in my app.py (Inserting into the association table)

 new_show = show.insert().values(
artist_id = form.artist_id.data,
venue_id = form.venue_id.data ,
start_time = form.start_time.data
)
db.session.execute(new_show)
db.session.commit()