Es gibt eine Tabelle mit einer ähnlichen Struktur, und ich habe sie durch Verwendung von Polymorphismus = Polymorphismus zu einer DRY-Struktur gemacht. Aus jeder Tabelle wurde es notwendig, eine Viele-zu-Viele-Beziehung zu derselben separaten Tabelle zu haben.
SQL Alchemy kann abhängig von der Tabellenstruktur drei Arten von Polymorphismus verwenden. Die Anzahl der Tabellen unter der Annahme, dass es eine Basisklasse und zwei abgeleitete Klassen gibt, wird ebenfalls beschrieben.
Aufgrund der externen Datenbank usw. haben wir diesmal die Vererbung von Betontabellen übernommen.
SQL Alchemy kann viele zu viele verarbeiten, ohne die Zwischentabellen zu kennen. Zitiert aus dem Beispiel im offiziellen Handbuch. Ein Muster, in dem ein Blog-Artikel mehrere Schlüsselwörter enthält.
post.keywords.append(Keyword('wendy'))
Angenommen, jedes Formular mit ähnlicher Konfiguration verfügt über mehrere Tags. Es gibt vier Tabellen: Tags, jede Form x 2, und eine Zwischentabelle.
# -*- coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.ext.declarative import *
from sqlalchemy.orm import *
from sqlalchemy_utils import *
base = declarative_base()
#Die Zwischentabelle muss keine Klasse sein.
assoc = Table('assoc', base.metadata,
Column('aform_id', Integer, ForeignKey('AForm.id')),
Column('bform_id', Integer, ForeignKey('BForm.id')),
Column('tag_id', Integer, ForeignKey('Tag.id'))
)
class Tag(base):
__tablename__ = 'Tag'
id = Column(Integer, primary_key = True)
name = Column(String)
#Auch wenn Sie es nicht direkt verwenden, tritt ohne diese Definition ein Fehler auf.
#Durch Angabe von backref das Gegenteil[AB]Die Beziehungsdefinition von Form kann weggelassen werden.
aform = relationship('AForm', secondary = assoc, backref = 'atag')
bform = relationship('BForm', secondary = assoc, backref = 'btag')
class Form(AbstractConcreteBase, base):
id = Column(Integer, primary_key = True)
amount = Column(Integer)
@declared_attr
def __tablename__(cls):
return cls.__name__
@declared_attr
def __mapper_args__(cls):
return {
'polymorphic_identity': cls.__name__,
'concrete':True
}
class AForm(Form, base):
pass
class BForm(Form, base):
b_only = Column(String(10))
db_uri = 'sqlite:////tmp/m2m.sqlite'
engine = create_engine(db_uri, echo =True)
if database_exists(engine.url):
drop_database(db_uri)
create_database(engine.url)
base.metadata.create_all(bind = engine)
Session = sessionmaker(bind = engine)
session = Session()
#Da atag für AForm und btag für BForm definiert ist, müssen sie separat aufgerufen werden.
a = AForm(amount = 100)
atag = Tag(name = 'booked')
a.atag.append(atag)
session.add(a)
f = BForm(amount = 200)
tag = Tag(name = 'canceled')
f.btag.append(tag)
session.add(f)
session.commit()
#Es ist auch möglich, sie unten dynamisch aufzurufen.
getattr(btag, f.__class__.__name__.lower()).append(f)
forms=session.query(AForm).all()
for f in forms:
print(f)
print(f.atag[0].name)
Sie können zwar ohne Kenntnis der Zwischentabelle arbeiten, aber da atag für AForm und btag für BForm definiert ist, müssen diese separat aufgerufen werden. Es ist jedoch möglich, mit getattr eine Methodenreferenz aus dem Klassennamen des Objekts zu generieren und diese in die Methodenkette aufzunehmen.
Erneut veröffentlichen
getattr(tag, b.__class__.__name__.lower()).append(b)
Verwirrend! Es kann eine Meinung geben, dass es so geschrieben werden sollte. Dies hängt vom Codierungsstil und der Anzahl der abgeleiteten Klassen ab.
if isinstance(f, AForm):
tag.aform.append(f)
Recommended Posts