{{tag>dev python flask orm db sqlalchemy}} :TODO_DOCUPDATE: ====== Flask-SQLAlchemy : relation one-to-many ====== Quelques notes à propos de l'implémentation d'une relation un à plusieurs (one to many) avec l'extension Flask-SQLAlchemy. Pour illustrer le concept on prend un exemple rudimentaire : {{ex_mcd_shop_products.png}} MCD via diagramme UML * Un magasin (Shop) vend un ou plusieurs produits (Product); * Un produit est stocké dans un seul magasin. ===== Implémentation ===== Ci-dessous l'application Flask minimaliste implémentant les deux classes du modèle et la relation one-to-many. from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Shop(db.Model): __tablename__ = 'shops' id = db.Column(db.Integer, primary_key=True, index=True) name = db.Column(db.String(80), unique=True, index=True) products = db.relationship("Product", back_populates="shop", lazy='dynamic') def add_product(self, product): if self.id is None : # Le magasin doit exister en base avant d'ajouter un produit db.session.add(self) db.session.commit() product.shop_id = self.id db.session.add(product) db.session.commit() class Product(db.Model): __tablename__ = 'products' id = db.Column(db.Integer, primary_key=True, index=True) name = db.Column(db.String(80), unique=True, index=True) price = db.Column(db.Float(precision=2)) shop_id = db.Column(db.Integer, db.ForeignKey('shops.id'), unique=False, nullable=False) shop = db.relationship("Shop", back_populates="products") # Création de l'application # On utilise la variable __name__ pour définir le nom du module courant # comme root applicatif pour notre application flask app = Flask(__name__) # Le chemin vers la base SQLite est relatif au dossier de l'application flask app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db" # Initialiser l'application Flask par l'intermédiaire de l'extension db.init_app(app) * Lignes 7 et 25 : les classes doivent hériter de db.Model pour que les objets puissent être enregistrés dans la base de données; * Pour chaque attribut, on définit un type valide pour le stockage en base de données; ===== La relation one-to-many ===== ==== L'option lazy="dynamic" de la méthode db.relationship ==== A la ligne 12, on peut voir que l'option **''lazy="dynamic"''** est utilisée pour définir la relation. Lorsque cette option est utilisée, l'attribut ''Shop.products'' **ne retourne plus directement la liste complète** de tous les produits désignés par la relation. Au lieu de cela, ''Shop.products'' retourne un objet de type requête : cela permet notamment de **définir des critères de sélection**. ===== Test et utilisation ===== Pour tester l'implémentation, on peut lancer l'application flask en mode interactif : flask shell >>> # Afficher les références >>> dir() >>> # Création de la base >>> db.drop_all() >>> db.create_all() >>> # Instanciation d'un magasin et de quelques produits >>> l = Shop() >>> l.name = "LouerMoi" >>> db.session.add(l) >>> db.session.commit() >>> p = Product() >>> p.name = "Ponceuse Botch" >>> p.price = 59.90 >>> >>> t = Product() >>> t.name = "Tronconeuse Botch" >>> t.price = 169.99 >>> >>> l.add_product(p) >>> l.add_product(t) >>> # Récupère tous les produits du magasin >>> l.products.all() >>> # Ne récupérer que les produits dont le prix est supérieur à 60€ >>> l.products.filter(Product.price > 60.0).all() >>> # Utilisation de la fonction LIKE >>> l.products.filter(Product.name.like('%pon%')).all() ===== Références ===== * [[https://pratapsharma.io/flask-sql-alchemy-one-to-many-relationship/|Mise en oeuvre d'une relation one-to-many avec Flask-SQLAlchemy]] * [[https://www.digitalocean.com/community/tutorials/how-to-use-one-to-many-database-relationships-with-flask-sqlalchemy|La relation one-to-many avec Flask-SQLAlchemy (digitalocean.com)]] * https://www.geeksforgeeks.org/python/sqlalchemy-cascading-deletes/ * [[https://www.peterspython.com/fr/blog/sqlalchemy-utilisation-de-cascade-deletes-pour-supprimer-des-objets-connexes|Cascader la suppression des objets enfants (peterspython.com)]]