Колба склалхімія багато-до-багатьох вставляє дані


79

Я намагаюся встановити відношення багато-до-багатьох тут у 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?

Відповіді:


147

Вам не потрібно нічого додавати безпосередньо до вашої таблиці асоціацій, SQLAlchemy зробить це. Це більш-менш із документації SQLAlchemy :

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

14
Скажімо, мої учні вже існують у таблиці. Як я можу додати їх до класу без необхідності кожного разу запитувати цілі дані для кожного учня (лише за допомогою клавіші попереднього вибору)?
axwell

@axwell, Якщо вам часто потрібні учні для класу (тобто, коли ви перевіряєте оновлення), ви можете налаштувати стосунки з ледачим = 'підзапитом' так: 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}, )
Edword

20

По-перше, student_identifierвизначається як таблиця відображення SQLAlchemy, а не база даних.

Зазвичай, якщо у вас належним чином налаштовані всі зв'язки між моделями та об'єктами таблиці відображення, вам потрібно буде мати справу лише з пов'язаними моделями (шляхом додавання об'єктів моделі у зв'язок InstrumentList), щоб вставити дані в таблиці відображення, наприклад, відповідь @ мехді-садегі, поданий вище.

Однак справді є спосіб вставити безпосередньо в таблиці відображення, якщо ви не хочете налаштовувати зв'язок. Наприклад:

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

Після цього ви зможете побачити, що рядок відносин багато-до-багатьох вставляється в student_identifierтаблицю відображення. Не забудьте зробити коміт після виконання кожного оператора SQL, як це робиться під час транзакції.

Сподіваюся, що це допоможе вам з альтернативним підходом.


як я можу імпортувати цю таблицю відображення або таблицю асоціацій?
jibin mathew

@jibinmathew так само, як і з класами та іншими символами.
Деві

@jibinmathew У мене також виникають проблеми при імпорті таблиці асоціацій, тому я імпортую таблицю локально, саме в тому місці, де я це називаю.
Три

1
@GofyandKitty, який може бути показником кругової залежності / імпорту у вашій основі коду, так що вам потрібно використовувати локальний імпорт (для надання простору імен), щоб він працював.
Деві

1
Велике спасибі, що поділилися цим рішенням. Ти буквально врятував мене
Чідібере

-1

Щоб розширити відповідь коров'ячих гілків, ви також можете додати кілька записів одночасно, використовуючи 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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.