diff --git a/ideas/resources.md b/ideas/resources.md index 2cc8ede..03fda9d 100644 --- a/ideas/resources.md +++ b/ideas/resources.md @@ -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*. * [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 * [Sam & Max](http://sametmax.com) diff --git a/source/part-2-deployment/docker.adoc b/source/part-2-deployment/docker.adoc new file mode 100644 index 0000000..51ca1c9 --- /dev/null +++ b/source/part-2-deployment/docker.adoc @@ -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. \ No newline at end of file diff --git a/source/part-3-django-concepts/models.adoc b/source/part-3-django-concepts/models.adoc index 3d721ae..fb5a851 100644 --- a/source/part-3-django-concepts/models.adoc +++ b/source/part-3-django-concepts/models.adoc @@ -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`. === 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 @@ -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 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] ---- 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. <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 @@ -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. +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: * `ordering` pour spécifier un ordre de récupération spécifique. diff --git a/source/part-3-django-concepts/templates.adoc b/source/part-3-django-concepts/templates.adoc index 87444c7..c604e69 100644 --- a/source/part-3-django-concepts/templates.adoc +++ b/source/part-3-django-concepts/templates.adoc @@ -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', + .... + ], +}, +----