Merge branch 'master' of https://grimbox.be/git/fred/gwift-book into master
This commit is contained in:
commit
04b493fea3
|
@ -5,6 +5,15 @@
|
||||||
* [Two scoops of Django](http://twoscoopspress.com/). Ce livre couvre les principaux concepts de Django. L'avantage est qu'on peut l'ouvrir au hasard et lire un chapitre sans devoir lire les précédents. Ce livre-ci ne constitue cependant pas un tutorial pour développer une application Django *from-scratch*.
|
* [Two scoops of Django](http://twoscoopspress.com/). Ce livre couvre les principaux concepts de Django. L'avantage est qu'on peut l'ouvrir au hasard et lire un chapitre sans devoir lire les précédents. Ce livre-ci ne constitue cependant pas un tutorial pour développer une application Django *from-scratch*.
|
||||||
* [Django Design Patterns](https://www.packtpub.com/web-development/django-design-patterns-and-best-practices), d'Arun Ravindran.
|
* [Django Design Patterns](https://www.packtpub.com/web-development/django-design-patterns-and-best-practices), d'Arun Ravindran.
|
||||||
|
|
||||||
|
## Sur le Web
|
||||||
|
|
||||||
|
* [Books by Agiliq](https://books.agiliq.com/en/latest/README.html) - Ils ont de tout, dont certains particulièrement utiles:
|
||||||
|
* [Django Admin Cookbook](https://books.agiliq.com/projects/django-admin-cookbook/) - pour Django 2.0, mais toujours d'actualité.
|
||||||
|
* [Django ORM](https://books.agiliq.com/projects/django-orm-cookbook/) - Idem (Django 2.0), mais cible précisément les fonctions de l'ORM.
|
||||||
|
* [Building APIs with Django and Django Rest Framework](http://books.agiliq.com/projects/django-api-polls-tutorial/), qu'on n'aborde pas ici ;-)
|
||||||
|
|
||||||
|
Et plein d'autres sucreries.
|
||||||
|
|
||||||
## Sites
|
## Sites
|
||||||
|
|
||||||
* [Sam & Max](http://sametmax.com)
|
* [Sam & Max](http://sametmax.com)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
(c/c Ced' - 2020-01-24)
|
||||||
|
|
||||||
|
Ça y est, j'ai fait un test sur mon portable avec docker et cookiecutter pour django.
|
||||||
|
|
||||||
|
D'abords, après avoir installer docker-compose et les dépendances sous debian, tu dois t'ajouter dans le groupe docker, sinon il faut être root pour utiliser docker.
|
||||||
|
Ensuite, j'ai relancé mon pc car juste relancé un shell n'a pas suffit pour que je puisse utiliser docker avec mon compte.
|
||||||
|
|
||||||
|
Bon après c'est facile, un petit virtualenv pour cookiecutter, suivit d'une installation du template django.
|
||||||
|
Et puis j'ai suivi sans t https://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html
|
||||||
|
|
||||||
|
Alors, il télécharge les images, fait un petit update, installe les dépendances de dev, install les requirement pip ...
|
||||||
|
|
||||||
|
Du coup, ça prend vite de la place:
|
||||||
|
image.png
|
||||||
|
|
||||||
|
L'image de base python passe de 179 à 740 MB. Et là j'en ai pour presque 1,5 GB d'un coup.
|
||||||
|
|
||||||
|
Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien faire ou presque.
|
|
@ -70,6 +70,8 @@ A partir de maintenant, on peut accéder à nos propriétés de la manière suiv
|
||||||
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`.
|
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
|
=== 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
|
* 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
|
* https://docs.djangoproject.com/en/1.9/ref/models/querysets/#django.db.models.query.QuerySet.iterator
|
||||||
|
@ -81,8 +83,28 @@ L'ORM de Django (et donc, chacune des classes qui composent votre modèle) propo
|
||||||
* Les querysets, qui permettent de filtrer des ensembles ou sous-ensemble d'objets. Les querysets peuvent s'imbriquer, pour ajouter
|
* 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.
|
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 :-).
|
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]
|
[source,python]
|
||||||
----
|
----
|
||||||
from core.models import Wish
|
from core.models import Wish
|
||||||
|
@ -92,8 +114,35 @@ Wish.objects.filter(name__icontains="test").filter(name__icontains="too") <2>
|
||||||
----
|
----
|
||||||
<1> Ca, c'est notre manager.
|
<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".
|
<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
|
||||||
|
|
||||||
|
@ -115,6 +164,8 @@ class Wish(models.Model):
|
||||||
----
|
----
|
||||||
<1> On définit un ordre par défaut, directement au niveau du modèle. Cela ne signifie pas qu'il ne sera pas possible de modifier cet ordre (la méthode `order_by` existe et peut être chaînée à n'importe quel queryset). D'où l'intérêt de tester ce type de comportement, dans la mesure où un `top 1` dans votre code pourrait être modifié simplement par cette petite information.
|
<1> On définit un ordre par défaut, directement au niveau du modèle. Cela ne signifie pas qu'il ne sera pas possible de modifier cet ordre (la méthode `order_by` existe et peut être chaînée à n'importe quel queryset). D'où l'intérêt de tester ce type de comportement, dans la mesure où un `top 1` dans votre code pourrait être modifié simplement par cette petite information.
|
||||||
|
|
||||||
|
Pour sélectionner un objet au pif : `return Category.objects.order_by("?").first()`
|
||||||
|
|
||||||
Les propriétés de la classe Meta les plus utiles sont les suivates:
|
Les propriétés de la classe Meta les plus utiles sont les suivates:
|
||||||
|
|
||||||
* `ordering` pour spécifier un ordre de récupération spécifique.
|
* `ordering` pour spécifier un ordre de récupération spécifique.
|
||||||
|
|
|
@ -232,4 +232,34 @@ def wishlists_list():
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
|
=== Contexts Processors
|
||||||
|
|
||||||
|
Un `context processor` permet d'ajouter des informations par défaut à un contexte (le dictionnaire qu'on passe de la vue au template).
|
||||||
|
L'idée est d'ajouter une fonction à un module Python à notre projet, puis de le référencer parmi
|
||||||
|
les CONTEXT_PROCESSORS de nos paramètres généraux. Cette fonction doit peupler un dictionnaire, et les clés de ce dictionnaire seront
|
||||||
|
directement ajoutées à tout autre dictionnaire/contexte passé à une vue. Par exemple:
|
||||||
|
|
||||||
|
(cf. https://stackoverflow.com/questions/60515797/default-context-for-all-pages-django[StackOverflow] - à retravailler)
|
||||||
|
|
||||||
|
[source,python]
|
||||||
|
----
|
||||||
|
from product.models import SubCategory, Category
|
||||||
|
|
||||||
|
|
||||||
|
def add_variable_to_context(request):
|
||||||
|
return {
|
||||||
|
'subCategories': SubCategory.objects.order_by('id').all(),
|
||||||
|
'categories': Category.objects.order_by("id").all(),
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
[source,python]
|
||||||
|
----
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
....
|
||||||
|
'core.context_processors.add_variable_to_context',
|
||||||
|
....
|
||||||
|
],
|
||||||
|
},
|
||||||
|
----
|
||||||
|
|
Loading…
Reference in New Issue