Patrimoine
Parmi les différents types d'héritage de modèle ORM, ormar en supporte actuellement deux:
- Mélangé à
- Héritage de table concret (parent défini sur abstract = True)
Types d'héritage
Un bref résumé des différents types d'héritage:
- Mixins[Support]-Ne sous-classez pas ormar. Model, définissez simplement les champs qui seront utilisés ultérieurement sur les différents modèles (par exemple, created_date et updated_date sur chaque modèle), seule la table de création du modèle réel est disponible, mais ajoutez les champs des mixins.
- Concrète Table Héritage[SUPPORTED]-signifie que les parents sont marqués comme abstraits et que chaque enfant a sa propre table contenant les colonnes du parent et ses propres colonnes enfants, un peu comme Mixins, mais le parent est aussi un modèle.
- héritage de table unique[non pris en charge]-signifie qu 'une seule table est créée, les champs sont une combinaison/somme du modèle parent et de tous les sous-modèles, mais le sous-modèle utilise uniquement un sous-ensemble des colonnes de la base de données (tous les modèles parents et leurs propres colonnes, en ignorant les autres sous-modèles).
- Multiple/Join Table Héritage[Non supporté]-signifie qu 'une partie des colonnes sont enregistrées sur le modèle parent et une partie sur le modèle enfant, elles sont connectées les unes aux autres par une relation un-à-un, et les deux modèles sont manipulés en arrière-plan immédiatement
- Modèle proxy[non supporté]-signifie que seul le parent possède une table réelle et que les enfants ajoutent simplement des méthodes, modifient les paramètres, etc.
Mélangé à
Pour utiliser Mixins, il suffit de définir une classe qui n'hérite pas d'ormar. Model, mais qui définit ormar. Fields comme variable de classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
!!!tip Notez que Mixin n'est pas un modèle, vous devez donc toujours hériter de l'ormar.Model et définir le champ ormar_config dans le modèle final.
La classe Catégorie ci-dessus aura quatre champs supplémentaires: created_date, updated_date, created_by et Updated_by.
Une seule table est créée pour la catégorie du modèle (catégorie), où le champ catégorie est combiné avec tous les champs Mixins.
Notez que Mixin dans le nom de la classe est facultatif, mais c'est une bonne pratique Python.
Héritage de table spécifique
Conceptuellement, l'héritage de table concret est très similaire à Mixins, mais utilise le vrai modèle. ormar comme classe de base.
!!!avertit que la classe de base a défini Abstract=True dans l'objet ormar_config, ce qui lève une erreur de définition de modélisation si vous essayez d'hériter d'une classe de balisage non abstraite.
Puisque ce modèle abstrait n'est jamais initialisé, vous pouvez ignorer les métadonnées et les bases de données dans sa définition ormar_config.
Mais si vous le fournissez, il sera hérité, de sorte que vous n'aurez pas à fournir les métadonnées et la base de données dans la classe finale/concrète.
Notez que vous pouvez toujours le remplacer dans une sous-classe/classe spécifique si vous le souhaitez.
Plus important encore, au moins une classe de la chaîne d'héritage doit fournir la base de données et les métadonnées, sinon une erreur sera générée.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
La liste des options/paramètres hérités est la suivante: métadonnées, bases de données et contraintes.
En plus de cela, bien sûr, tous les champs de la classe de base sont combinés et créés dans des tables concrètes du modèle final.
!!!Remarquez que vous n'avez pas besoin de fournir abstarct = False dans la classe finale-c'est le paramètre par défaut qui n'est pas hérité.
Redéfinir un champ dans une sous-classe
Notez que vous pouvez redéfinir les champs précédemment créés comme vous le feriez avec l'héritage de classe Python normal.
Chaque fois que vous définissez un champ avec le même nom et une nouvelle définition, il remplace complètement le champ défini précédemment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
!!!avertit que si vous déclarez une contrainte UniqueColumns avec un nom de colonne, le modèle final doit déclarer une colonne portant le même nom. sinon, une erreur ModelDefinitionError sera levée.
1 2 3 4 5 6 | |
Relations héritées
Vous pouvez déclarer une relation à chaque étape de l'héritage, que ce soit dans une classe parente ou une sous-classe.
Lorsque vous définissez une relation au niveau d'un sous-modèle, elle remplace la relation définie dans le modèle parent (si le même nom de champ est utilisé), ou elle n'est accessible que par ce sous-modèle si vous définissez une nouvelle relation.
Lorsque vous héritez d'une relation, vous devez toujours faire attention au paramètre related_name, qui doit être unique dans le modèle pertinent lorsque vous définissez plusieurs sous-classes qui héritent de la même relation.
Si vous ne fournissez pas l'argument related_name, ormar calcule pour vous. cela s'applique à l'héritage, car tous les sous-modèles doivent avoir des noms de classe différents qui sont utilisés pour calculer le nom related_name par défaut (classe.name.lower()+'s').
Toutefois, si vous fournissez un nom_related, ce nom ne peut pas être réutilisé dans tous les sous-modèles car ils se superposent mutuellement du côté du modèle associé.
Vous avez donc deux options:
- Redéfinir les champs relationnels dans le sous-modèle et fournir manuellement un paramètre_name related différent
- laisse le related_name d'ormar traiter-> l'ajustement automatique est: related_name + "_" + nom de la table du sous-modèle
Cela peut sembler compliqué, mais regardons l'exemple suivant:
Relations de clé étrangère
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Maintenant, lorsque vous examinez les champs sur le modèle Personne, vous obtenez:
1 2 3 4 5 6 7 8 9 | |
Remarquez comment vous avez des champs camions et bus qui conduisent à des catégories de camions et bus appartenant à cette personne. il n'y a pas de paramètre related_name, donc le nom par défaut est utilisé.
Les voitures copropriétaires simultanées doivent être référencées par les suffixes coowned_trucks et coowned_buses. Ormar ajoute les suffixes_trucks et_buses tirés des noms des tables de sous-modèles.
Ça a l'air bien, mais le nom par défaut pour les camions appartenant à notre propre entreprise est OK (camion), mais les bus sont laids, alors comment pouvons-nous le changer?
La solution est très simple: il suffit de redéfinir les champs de la classe Bus et de fournir un paramètre related_name différent.
1 2 3 4 5 6 7 | |
Maintenant, les colonnes semblent beaucoup mieux.
1 2 3 4 5 6 7 8 9 | |
!!!Remarque Vous pouvez également fournir un nom_related pour le champ propriétaire, ce qui ajoutera le suffixe correct.
1 2 3 | |
Plusieurs à plusieurs relations
De même, vous pouvez hériter d'un modèle qui a déclaré une relation ManyToMany, mais avec une différence substantielle-le modèle Through.
Puisque le modèle Through sera capable de contenir d'autres champs, et qu 'il ne lie désormais que deux tables (de et vers une table), chaque enfant qui hérite d'un champ relationnel m2m doit avoir un modèle Through distinct.
Bien sûr, vous pouvez remplacer les relations dans chaque sous-modèle, mais cela nécessite un code supplémentaire et détruit le sens de l'héritage entier. si vous êtes d'accord avec la convention de nommage par défaut, Ormar s'en occupera pour vous, et vous pouvez toujours remplacer manuellement la convention dans les enfants si vous le souhaitez.
Encore une fois, regardons des exemples pour saisir plus facilement le concept.
Nous allons modifier l'exemple précédent décrit ci-dessus pour utiliser la relation m2m de co_owners.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
Ormar modifie automatiquement le nom related_name du champ pour inclure le nom de la table du sous-modèle. le nom par défaut est le nom original related_+ '_' + nom de la sous-table.
Ainsi, pour la classe Truck2, la relation définie owner: Person = ormar.ForeignKey(Person, related_name="owned") devient owned_trucks2
Vous pouvez vérifier les noms en examinant la liste des champs présents sur le modèle de personne.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Mais ce n'est pas tout-c'est la structure interne d'ormar, mais elle affecte la structure des données dans la base de données, alors examinons le modèle de passage direct des modèles Bus2 et Truck2.
1 2 3 4 5 6 7 8 9 | |
Comme vous pouvez le voir ci-dessus, ormar a cloné le modèle Through pour chaque sous-classe et a ajouté le nom de la sous-classe à la fin, tout en changeant le nom de la table pour le champ cloné, en utilisant le nom de la table pour les enfants.
Notez que non seulement le modèle original n'est pas utilisé, mais que les tables de ce modèle sont également supprimées des métadonnées:
1 2 3 | |
Notez donc que si vous introduisez l'héritage jusqu 'au bout et convertissez le modèle en un modèle parent abstrait, vous risquez de perdre des données dans la table si vous ne faites pas attention.
!!!Notez que le nom de table original et le nom de modèle du modèle Through ne sont jamais utilisés. seules les tables de modèle clonées sont créées et utilisées.
Attention!!!Notez que chaque sous-classe du modèle pour lequel la relation ManyToMany est définie génère un nouveau modèle Through, ce qui signifie également de nouvelles tables de base de données.
1 2 | |
Exclure le champ parent
Ormar vous permet de sauter certains champs du modèle parent dans le modèle hérité.
!!!Notez que le même comportement peut être obtenu en divisant le modèle en modèles plus abstraits et en mixins-c'est la façon préférée normalement.
Pour ignorer certains champs dans un sous-modèle, liste tous les champs à ignorer model.ormar_config.exclude_parent_fields paramètres comme suit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
Notez que vous n'avez qu'à fournir le nom du champ et que cela exclut le champ parent, quel que soit le modèle parent d'où provient le champ.
!!!Remarque Notez que si vous souhaitez remplacer un champ dans un sous-modèle, vous n'avez pas besoin de l'exclure, il suffit de remplacer la déclaration de champ dans le sous-modèle par le même nom.
Attention, ce comportement peut confondre mypy et les vérificateurs de type statique, mais l'accès à un champ inexistant échouera à l'exécution. c'est pourquoi la classe de base fractionnée est préférée.
Le même effet peut être obtenu en divisant la classe de base, par exemple:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
De cette façon, vous pouvez hériter de la création et de la mise à jour des classes si nécessaire, sinon vous ne pouvez hériter que d'une seule classe.