Flask sqlalchemy viele-zu-viele Daten einfügen

77

Ich versuche hier in Flask-SQLAlchemy eine Viele-zu-Viele-Beziehung herzustellen , aber es scheint, dass ich nicht weiß, wie ich die "Viele-zu-Viele-Identifikator-Datenbank" füllen soll . Könnten Sie mir bitte helfen zu verstehen, was ich falsch mache und wie es aussehen soll?

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)

und dann meine Identifikationsdatenbank:

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

Bisher sieht es so aus, wenn ich versuche, die Daten in die Datenbank einzufügen.

# User
user1 = User(
            user_fistName='John',
            user_lastName='Doe',
            user_email='[email protected]')

user2 = User(
            user_fistName='Jack',
            user_lastName='Doe',
            user_email='[email protected]')

user3 = User(
            user_fistName='Jane',
            user_lastName='Doe',
            user_email='[email protected]')

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

Mein Problem ist nun, wie füge ich der Many-to-Many-Datenbank hinzu, da ich wirklich kein 'student_identifier'-Objekt erstellen kann? Wenn ich könnte, hätte es vielleicht so aussehen können:

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

Wie soll ich mit ORM in eine Viele-zu-Viele-Tabelle einfügen?

Siegel
quelle

Antworten:

143

Sie müssen nichts direkt zu Ihrer Zuordnungstabelle hinzufügen, SQLAlchemy erledigt dies. Dies stammt mehr oder weniger aus SQLAlchemy-Dokumentationen :

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

Daher würde Ihre Stichprobe folgendermaßen aussehen:

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()
Mehdi Sadeghi
quelle
12
Nehmen wir an, meine Schüler existieren bereits in einer Tabelle. Wie füge ich sie einer Klasse hinzu, ohne jedes Mal die gesamten Daten für jeden Schüler abfragen zu müssen (nur mit dem Vorschlüssel)?
Axwell
@axwell, Wenn Sie häufig Schüler für den Unterricht benötigen (dh wenn Sie das Update überprüfen), können Sie die Beziehung zu faul = 'Unterabfrage' wie folgt einstellen: students = db.relationship("Student", secondary=student_identifier, lazy='subquery', backref=db.backref('classes', lazy=True))
Andrii Danyleiko
20

Zunächst einmal student_identifierwird als SQLAlchemy-Reflexionstabelle keine Datenbank definiert.

Wenn Sie alle Beziehungen zwischen Modellen und Reflexionstabellenobjekten ordnungsgemäß eingerichtet haben, müssen Sie sich normalerweise nur mit verwandten Modellen befassen (indem Sie Modellobjekte an die Beziehung InstrumentList anhängen), um Daten in Reflexionstabellen einzufügen, z. B. die Antwort @ Mehdi-Sadeghi oben zur Verfügung gestellt.

Es gibt jedoch tatsächlich eine Möglichkeit, direkt in Reflektionstabellen einzufügen, wenn Sie die Beziehung nicht einrichten möchten. Zum Beispiel:

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

Danach sollten Sie sehen können, dass eine Viele-zu-Viele-Beziehungszeile in die student_identifierReflexionstabelle eingefügt wird . Vergessen Sie nicht, ein Commit durchzuführen, nachdem Sie jede SQL-Anweisung wie in einer Transaktion ausgeführt haben.

Hoffe das hilft dir bei einem alternativen Ansatz.

Devy
quelle
Wie kann ich diese Reflexionstabelle oder Zuordnungstabelle importieren?
Jibin Mathew
@jibinmathew genau wie bei Klassen und anderen Symbolen.
Devy
@jibinmathew Ich habe auch ein Problem beim Importieren der Zuordnungstabelle, also importiere ich die Tabelle lokal, genau dort, wo ich das aufrufe.
Tri
1
@GofyandKitty, das ein Indikator für zirkuläre Abhängigkeit / Import in Ihrer Codebasis sein könnte, sodass Sie den lokalen Import (um einen Namespace bereitzustellen) verwenden müssen, damit dies funktioniert.
Devy
1
Vielen Dank für das Teilen dieser Lösung. Du hast mich buchstäblich gerettet
Chidiebere
-1

Um die Antwort auf Cowgills zu erweitern, können Sie auch mehrere Einträge gleichzeitig hinzufügen, indem Sie 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()
NMO
quelle