Working on models
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Fred 2021-04-05 20:53:29 +02:00
parent b0212568d9
commit 525fd98ac0
5 changed files with 111 additions and 110 deletions

View File

@ -1 +1 @@
<mxfile host="Electron" modified="2021-04-01T17:15:06.275Z" agent="5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="Eb_fxTyGTLjvrYEHfW4F" version="14.1.8" type="device"><diagram id="QauGiNaH4VtSwm0Mn54J" name="Page-1">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</diagram></mxfile>
<mxfile host="Electron" modified="2021-04-05T18:45:16.134Z" agent="5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="LKa1JIw04JDgKm4TxeIl" version="14.1.8" type="device"><diagram id="QauGiNaH4VtSwm0Mn54J" name="Page-1">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</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -4,4 +4,17 @@ Dans cette section, nous allons voir comment les migrations fonctionnent.
Dans une première version, elles peuvent sembler un peu magiques, dans la mesure où elles appliquent des modifications au niveau du schéma de données en se basant uniquement sur des modifications effectuées sur le modèle.
Pour repartir de notre exemple ci-dessus, nous avions un modèle reprenant quelques classes, et saupoudrées de propriétés.
Pour schématiser, chaque classe correspond à une table dans la base de données, tandis que que chaque propriété correspond à un champ de cette table.
Pour schématiser, chaque classe correspond à une table dans la base de données, tandis que que chaque propriété correspond à un champ de cette table.
Une migration consiste donc à appliquer un ensemble de modifications, qui exercent un ensemble de transformations, pour que le schéma de base de données corresponde au modèle de l'application.
Les migrations (comprendre les "_migrations du schéma de base de données_") sont intimement liées à la représentation d'un contexte fonctionnel. L'ajout d'une nouvelle information, d'un nouveau champ ou d'une nouvelle fonction peut s'accompagner de tables de données à mettre à jour ou de champs à étendre.
Toujours dans une optique de centralisation, les migrations sont directement embarquées au niveau du code. Le développeur s'occupe de créer les migrations en fonction des actions à entreprendre; ces migrations peuvent être retravaillées, _squashées_, ... et feront partie intégrante du processus de mise à jour de l'application.
A noter que les migrations n'appliqueront de modifications que si le schéma est impacté. Ajouter une propriété `related_name` sur une ForeignKey n'engendrera aucune nouvelle action de migration, puisque ce type d'action ne s'applique que sur l'ORM, et pas directement sur la base de données: au niveau des tables, rien ne change. Seul le code et le modèle sont impactés.
https://simpleisbetterthancomplex.com/tutorial/2016/07/26/how-to-reset-migrations.html[reset migrations].
> En gros, soit on supprime toutes les migrations (en conservant le fichier __init__.py), soit on réinitialise proprement les migrations avec un --fake-initial (sous réserve que toutes les personnes qui utilisent déjà le projet s'y conforment... Ce qui n'est pas gagné.

View File

@ -2,24 +2,33 @@
On va aborder la modélisation des objets en elle-même, qui s'apparente à la conception de la base de données.
Django utilise un modèle https://fr.wikipedia.org/wiki/Mapping_objet-relationnel[ORM] - c'est-à-dire que chaque objet peut s'apparenter à une table SQL, mais en ajoutant une couche propre au paradigme orienté objet. Il sera ainsi possible de définir facilement des notions d'héritage (tout en restant dans une forme d'héritage simple), la possibilité d'utiliser des propriétés spécifiques, des classes intermédiaires, ...
Django utilise un modèle https://fr.wikipedia.org/wiki/Mapping_objet-relationnel[ORM] - c'est-à-dire que chaque objet peut s'apparenter à une table SQL, mais en ajoutant une couche propre au paradigme orienté objet.
Il sera ainsi possible de définir facilement des notions d'héritage (tout en restant dans une forme d'héritage simple), la possibilité d'utiliser des propriétés spécifiques, des classes intermédiaires, ...
L'avantage de tout ceci est que tout reste au niveau du code. Si l'on revient sur la méthodologie des douze facteurs, ce point concerne principalement la minimisation de la divergence entre les environnements d'exécution. Déployer une nouvelle instance de l'application pourra être réalisé directement à partir d'une seule et même commande, dans la mesure où *tout est embarqué au niveau du code*.
L'avantage de tout ceci est que tout reste au niveau du code.
Si nous revenons sur la méthodologie des douze facteurs, ce point-ci concerne principalement la minimisation de la divergence entre les environnements d'exécution.
Déployer une nouvelle instance de l'application pourra être réalisé directement à partir d'une seule et même commande, dans la mesure où *tout est embarqué au niveau du code*.
Assez de blabla, on démarre !
=== Types de champs
=== Modélisation de base
==== Types de champs
=== Clés étrangères et relations
==== Clés étrangères et relations
. ForeignKey
. ManyToManyField
. OneToOneField
Dans les examples ci-dessus, nous avons vu les relations multiples (1-N), représentées par des *ForeignKey* d'une classe A vers une classe B. Il existe également les champs de type *ManyToManyField*, afin de représenter une relation N-N. Les champs de type *OneToOneField*, pour représenter une relation 1-1.
Dans les examples ci-dessus, nous avons vu les relations multiples (1-N), représentées par des clés étrangères (**ForeignKey**) d'une classe A vers une classe B.
Pour représenter d'autres types de relations, il existe également les champs de type *ManyToManyField*, afin de représenter une relation N-N. Les champs de type *OneToOneField*, pour représenter une relation 1-1.
Dans notre modèle ci-dessus, nous n'avons jusqu'à présent eu besoin que des relations 1-N: la première entre les listes de souhaits et les souhaits; la seconde entre les souhaits et les parts.
Dans notre modèle ci-dessus, nous n'avons jusqu'à présent eu besoin que des relations 1-N:
. La première entre les listes de souhaits et les souhaits;
. La seconde entre les souhaits et les parts.
[source,python]
----
@ -49,102 +58,27 @@ class Item(models.Model):
wishlist = models.ForeignKey(Wishlist, related_name='items')
----
A partir de maintenant, on peut accéder à nos propriétés de la manière suivante:
NOTE: Si, dans une classe A, plusieurs relations sont liées à une classe B, Django ne saura pas à quoi correspondra la relation inverse. Pour palier à ce problème, nous fixons une valeur à l'attribut `related_name`. Par facilité (et pas conventions), prenez l'habitude de toujours ajouter cet attribut. Votre modèle gagnera en cohérence et en lisibilité.
A partir de maintenant, nous pouvons accéder à nos propriétés de la manière suivante:
[source,python]
----
# python manage.py shell
>>> from wish.models import Wishlist, Item
>>> w = Wishlist('Liste de test', 'description')
>>> w = Wishlist.create('Liste de test', 'description')
>>> i = Item.create('Element de test', 'description', w)
>>> wishlist = Wishlist.create('Liste de test', 'description')
>>> item = Item.create('Element de test', 'description', w)
>>>
>>> i.wishlist
>>> item.wishlist
<Wishlist: Wishlist object>
>>>
>>> w.items.all()
>>> wishlist.items.all()
[<Item: Item object>]
----
Remarque: si, dans une classe A, plusieurs relations sont liées à une classe B, Django ne saura pas à quoi correspondra la relation inverse. Pour palier à ce problème et pour gagner en cohérence, on fixe alors une valeur à l'attribut `related_name`.
=== Querysets et managers
NOTE : faudra sortir les queryset du chapitre...
* http://stackoverflow.com/questions/12681653/when-to-use-or-not-use-iterator-in-the-django-orm
* https://docs.djangoproject.com/en/1.9/ref/models/querysets/#django.db.models.query.QuerySet.iterator
* http://blog.etianen.com/blog/2013/06/08/django-querysets/
L'ORM de Django (et donc, chacune des classes qui composent votre modèle) propose par défaut deux objets hyper importants:
* Les managers, qui consistent en un point d'entrée pour accéder aux objets persistants
* Les querysets, qui permettent de filtrer des ensembles ou sous-ensemble d'objets. Les querysets peuvent s'imbriquer, pour ajouter
d'autres filtres à des filtres existants.
Ces deux propriétés vont de paire; par défaut, chaque classe de votre modèle propose un attribut `objects`, qui correspond
à un manager (ou un gestionnaire, si vous préférez). Ce gestionnaire constitue l'interface par laquelle vous accéderez à la base de données. Mais pour cela, vous aurez aussi besoin d'appliquer certains requêtes ou filtres. Et pour cela, vous aurez besoin des `querysets`, qui consistent en des ... ensembles de requêtes :-).
Si on veut connaître la requête SQL sous-jacente à l'exécution du queryset, il suffit d'appeler la fonction str() sur la propriété `query`:
[source,python]
----
queryset = Wishlist.objects.all()
print(queryset.query)
----
Conditions AND et OR sur un queryset
Pour un `AND`, il suffit de chaîner les conditions. ** trouver un exemple ici ** :-)
Mais en gros : bidule.objects.filter(condition1, condition2)
Il existe deux autres options : combiner deux querysets avec l'opérateur `&` ou combiner des Q objects avec ce même opérateur.
Soit encore combiner des filtres:
[source,python]
----
from core.models import Wish
Wish.objects <1>
Wish.objects.filter(name__icontains="test").filter(name__icontains="too") <2>
----
<1> Ca, c'est notre manager.
<2> Et là, on chaîne les requêtes pour composer une recherche sur tous les souhaits dont le nom contient (avec une casse insensible) la chaîne "test" et dont le nom contient la chaîne "too".
Pour un 'OR', on a deux options :
. Soit passer par deux querysets, typiuqment `queryset1 | queryset2`
. Soit passer par des `Q objects`, que l'on trouve dans le namespace `django.db.models`.
[source,python]
----
from django.db.models import Q
condition1 = Q(...)
condition2 = Q(...)
bidule.objects.filter(condition1 | condition2)
----
L'opérateur inverse (_NOT_)
Idem que ci-dessus : soit on utilise la méthode `exclude` sur le queryset, soit l'opérateur `~` sur un Q object;
Ajouter les sujets suivants :
. Prefetch
. select_related
=== Aggregate vs. Annotate
https://docs.djangoproject.com/en/3.1/topics/db/aggregation/
=== Metamodèle
==== Metamodèle
Quand on prend une classe (par exemple, `Wishlist` que l'on a défini ci-dessus), on voit qu'elle hérite par défaut de `models.Model`. On peut regarder les propriétés définies dans cette classe en analysant le fichier `lib\site-packages\django\models\base.py`. On y voit notamment que `models.Model` hérite de `ModelBase` au travers de https://pypi.python.org/pypi/six[six] pour la rétrocompatibilité vers Python 2.7.
@ -172,26 +106,8 @@ Les propriétés de la classe Meta les plus utiles sont les suivates:
* `verbose_name` pour indiquer le nom à utiliser au singulier pour définir votre classe
* `verbose_name_plural`, pour le pluriel.
=== Migrations
==== Shell
Les migrations (comprendre les "_migrations du schéma de base de données_") sont intimement liées à la représentation d'un contexte fonctionnel. L'ajout d'une nouvelle information, d'un nouveau champ ou d'une nouvelle fonction peut s'accompagner de tables de données à mettre à jour ou de champs à étendre.
Toujours dans une optique de centralisation, les migrations sont directement embarquées au niveau du code. Le développeur s'occupe de créer les migrations en fonction des actions à entreprendre; ces migrations peuvent être retravaillées, _squashées_, ... et feront partie intégrante du processus de mise à jour de l'application.
A noter que les migrations n'appliqueront de modifications que si le schéma est impacté. Ajouter une propriété `related_name` sur une ForeignKey n'engendrera aucune nouvelle action de migration, puisque ce type d'action ne s'applique que sur l'ORM, et pas directement sur la base de données: au niveau des tables, rien ne change. Seul le code et le modèle sont impactés.
https://simpleisbetterthancomplex.com/tutorial/2016/07/26/how-to-reset-migrations.html[reset migrations].
> En gros, soit on supprime toutes les migrations (en conservant le fichier __init__.py), soit on réinitialise proprement les migrations avec un --fake-initial (sous réserve que toutes les personnes qui utilisent déjà le projet s'y conforment... Ce qui n'est pas gagné.
=== Shell
=== Les validateurs
=== A retenir
==== Constructeurs

View File

@ -1,5 +1,73 @@
### Querysets & managers
* http://stackoverflow.com/questions/12681653/when-to-use-or-not-use-iterator-in-the-django-orm
* https://docs.djangoproject.com/en/1.9/ref/models/querysets/#django.db.models.query.QuerySet.iterator
* http://blog.etianen.com/blog/2013/06/08/django-querysets/
L'ORM de Django (et donc, chacune des classes qui composent votre modèle) propose par défaut deux objets hyper importants:
* Les managers, qui consistent en un point d'entrée pour accéder aux objets persistants
* Les querysets, qui permettent de filtrer des ensembles ou sous-ensemble d'objets. Les querysets peuvent s'imbriquer, pour ajouter
d'autres filtres à des filtres existants.
Ces deux propriétés vont de paire; par défaut, chaque classe de votre modèle propose un attribut `objects`, qui correspond
à un manager (ou un gestionnaire, si vous préférez). Ce gestionnaire constitue l'interface par laquelle vous accéderez à la base de données. Mais pour cela, vous aurez aussi besoin d'appliquer certains requêtes ou filtres. Et pour cela, vous aurez besoin des `querysets`, qui consistent en des ... ensembles de requêtes :-).
Si on veut connaître la requête SQL sous-jacente à l'exécution du queryset, il suffit d'appeler la fonction str() sur la propriété `query`:
[source,python]
----
queryset = Wishlist.objects.all()
print(queryset.query)
----
Conditions AND et OR sur un queryset
Pour un `AND`, il suffit de chaîner les conditions. ** trouver un exemple ici ** :-)
Mais en gros : bidule.objects.filter(condition1, condition2)
Il existe deux autres options : combiner deux querysets avec l'opérateur `&` ou combiner des Q objects avec ce même opérateur.
Soit encore combiner des filtres:
[source,python]
----
from core.models import Wish
Wish.objects <1>
Wish.objects.filter(name__icontains="test").filter(name__icontains="too") <2>
----
<1> Ca, c'est notre manager.
<2> Et là, on chaîne les requêtes pour composer une recherche sur tous les souhaits dont le nom contient (avec une casse insensible) la chaîne "test" et dont le nom contient la chaîne "too".
Pour un 'OR', on a deux options :
. Soit passer par deux querysets, typiuqment `queryset1 | queryset2`
. Soit passer par des `Q objects`, que l'on trouve dans le namespace `django.db.models`.
[source,python]
----
from django.db.models import Q
condition1 = Q(...)
condition2 = Q(...)
bidule.objects.filter(condition1 | condition2)
----
L'opérateur inverse (_NOT_)
Idem que ci-dessus : soit on utilise la méthode `exclude` sur le queryset, soit l'opérateur `~` sur un Q object;
Ajouter les sujets suivants :
. Prefetch
. select_related
#### Jointures
Pour appliquer une jointure sur un modèle, nous pouvons passer par les méthodes `select_related` et `prefetch_related`.
@ -29,3 +97,7 @@ informations = (
.iterator(chunk_size=1000)
)
----
=== Aggregate vs. Annotate
https://docs.djangoproject.com/en/3.1/topics/db/aggregation/