Il y a une table avec une structure similaire, et j'en ai fait une structure DRY en utilisant polymorphisme = polymorphisme. A partir de chaque table, il est devenu nécessaire d'avoir une relation plusieurs-à-plusieurs avec la même table séparée.
SQL Alchemy peut utiliser trois types de polymorphisme en fonction de la structure de la table. Le nombre de tables en supposant qu'il existe une classe de base et deux classes dérivées est également décrit.
--Héritage de table unique Placez toutes les tables dérivées dans une table. Le nombre de tables est de 1. --Héritage de la table conjointe La table de base et la table dérivée sont séparées. Le nombre de tables est de 3. --Héritage de table en béton N'a pas de classe de base dans la table, mais a une classe dérivée dans chaque table. Le nombre de tables est de 2.
En raison de la base de données externe, etc., nous avons adopté l'héritage de table en béton cette fois.
SQL Alchemy peut gérer plusieurs-à-plusieurs sans connaître les tables intermédiaires. Cité de l'échantillon dans le manuel officiel. Un modèle dans lequel un article de blog a plusieurs mots-clés.
post.keywords.append(Keyword('wendy'))
Supposons que chaque formulaire avec une configuration similaire possède plusieurs balises. Il existe quatre tableaux: les balises, chaque formulaire x 2 et une table intermédiaire.
# -*- coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.ext.declarative import *
from sqlalchemy.orm import *
from sqlalchemy_utils import *
base = declarative_base()
#La table intermédiaire n'a pas besoin d'être une classe.
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)
#Même si vous ne l'utilisez pas directement, une erreur se produira sans cette définition.
#En spécifiant backref, le contraire[AB]La définition de relation de forme peut être omise.
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()
#Puisque atag est défini pour AForm et btag est défini pour BForm, il est nécessaire de les appeler séparément.
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()
#Il est également possible de les appeler dynamiquement ci-dessous.
getattr(btag, f.__class__.__name__.lower()).append(f)
forms=session.query(AForm).all()
for f in forms:
print(f)
print(f.atag[0].name)
Il est vrai que vous pouvez opérer sans connaître la table intermédiaire, mais comme atag est défini pour AForm et btag est défini pour BForm, il est nécessaire de les appeler séparément. Cependant, il est possible d'utiliser getattr pour générer une référence de méthode à partir du nom de classe de l'objet et la joindre dans la chaîne de méthodes.
Republier
getattr(tag, b.__class__.__name__.lower()).append(b)
Déroutant! Il peut y avoir une opinion selon laquelle il devrait être écrit comme ceci. Cela dépendra du style de codage et du nombre de classes dérivées.
if isinstance(f, AForm):
tag.aform.append(f)
Recommended Posts