Django : Proofreading.
This commit is contained in:
parent
7341368eba
commit
5e69beabe4
|
@ -6,23 +6,26 @@ Julien Palard <julien@palard.fr>
|
||||||
|
|
||||||
https://mdk.fr
|
https://mdk.fr
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Introduce yourself!
|
Introduce yourself!
|
||||||
|
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
|
|
||||||
Django est une infrastructure d'applications web populaire et robuste.
|
Django est une infrastructure d’applications web populaire et robuste.
|
||||||
|
|
||||||
> The web framework for perfectionists with deadlines.
|
> The web framework for perfectionists with deadlines.
|
||||||
|
|
||||||
|
|
||||||
## Django : qui l'utilise ?
|
## Django : qui l’utilise ?
|
||||||
|
|
||||||
- Instagram, Pineterest, Mozilla, Disqus, BitBucket, …
|
- Instagram
|
||||||
|
- Pineterest
|
||||||
![](static/stats.png)
|
- Mozilla
|
||||||
|
- National Geographic
|
||||||
|
- [Washington Post](https://www.djangoproject.com/weblog/2005/dec/08/congvotes/)
|
||||||
|
- ...
|
||||||
|
|
||||||
|
|
||||||
## Vocabulaire
|
## Vocabulaire
|
||||||
|
@ -55,18 +58,18 @@ Une fois dans le projet, pour créer une application, une commande :
|
||||||
python manage.py startapp watch
|
python manage.py startapp watch
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
(et ajout dans `settings.py`)
|
(et ajout dans `settings.py`)
|
||||||
|
|
||||||
|
|
||||||
## La théorie — Modèle
|
## La théorie — Modèle
|
||||||
|
|
||||||
Un « modèle » est la description d'une table.
|
Un « modèle » est la description d’une table.
|
||||||
|
|
||||||
Ça rappelle un ORM, mais ça permet beaucoup plus de choses en Django.
|
Ça rappelle un ORM, mais ça permet beaucoup plus de choses en Django.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
- admin
|
- admin
|
||||||
- forms
|
- forms
|
||||||
|
@ -85,14 +88,14 @@ class Website(models.Model):
|
||||||
last_check = models.DateTimeField(auto_now_add=True)
|
last_check = models.DateTimeField(auto_now_add=True)
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Prendre le temps d'expliquer les fields (leur relation avec la DB), et
|
Prendre le temps d’expliquer les fields (leur relation avec la DB), et
|
||||||
les differents endroits ou Django peut reutiliser cette information
|
les differents endroits ou Django peut reutiliser cette information
|
||||||
(widgets, validation, ...).
|
(widgets, validation, ...).
|
||||||
|
|
||||||
|
|
||||||
## Première interface d'admin
|
## Première interface d’admin
|
||||||
|
|
||||||
En une ligne, pourquoi pas :
|
En une ligne, pourquoi pas :
|
||||||
|
|
||||||
|
@ -107,14 +110,14 @@ admin.site.register(Website)
|
||||||
- sqlite
|
- sqlite
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Leur faire croire 2 secondes qu'on va devoir s'installer et se
|
Leur faire croire 2 secondes qu’on va devoir s’installer et se
|
||||||
configurer un serveur de base de donnée :D
|
configurer un serveur de base de donnée :D
|
||||||
|
|
||||||
Leur expliquer que sqlite est utilisé dans les applications : pas
|
Leur expliquer que sqlite est utilisé dans les applications : pas
|
||||||
besoin d'installer un postgresql pour utiliser Firefox, pourtant
|
besoin d’installer un postgresql pour utiliser Firefox, pourtant
|
||||||
Firefox a besoin d'une base de donnée.
|
Firefox a besoin d’une base de donnée.
|
||||||
|
|
||||||
|
|
||||||
## La théorie — La DB
|
## La théorie — La DB
|
||||||
|
@ -124,15 +127,15 @@ python manage.py makemigrations
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
On expliquera plus tard, leur dire que ça crée la DB et que le but
|
On expliquera plus tard, leur dire que ça crée la DB et que le but
|
||||||
maintenant c'est surtout d'aller tester ça :)
|
maintenant c’est surtout d’aller tester ça :)
|
||||||
|
|
||||||
|
|
||||||
## L'interface d'administration
|
## L’interface d’administration
|
||||||
|
|
||||||
On a une DB, mais pas encore d'utilisateur admin dedans :
|
On a une DB, mais pas encore d’utilisateur admin dedans :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python manage.py createsuperuser
|
python manage.py createsuperuser
|
||||||
|
@ -154,15 +157,15 @@ cd project
|
||||||
python manage.py startapp watch
|
python manage.py startapp watch
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Biiien prendre le temps d'expliquer l'arborescence, de se promener,
|
Biiien prendre le temps d’expliquer l’arborescence, de se promener,
|
||||||
d'y lire les commentaires.
|
d’y lire les commentaires.
|
||||||
|
|
||||||
|
|
||||||
## La pratique
|
## La pratique
|
||||||
|
|
||||||
Ajout de l'app `watch` dans `project/settings.py` :
|
Ajout de l’app `watch` dans `project/settings.py` :
|
||||||
|
|
||||||
```python
|
```python
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
@ -185,7 +188,7 @@ class Website(models.Model):
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Première interface d'admin
|
## Première interface d’admin
|
||||||
|
|
||||||
Et ça dans `watch/admin.py`.
|
Et ça dans `watch/admin.py`.
|
||||||
|
|
||||||
|
@ -204,19 +207,19 @@ python manage.py makemigrations
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Expliquer les deux étapes.
|
Expliquer les deux étapes.
|
||||||
|
|
||||||
|
|
||||||
## Les modèles
|
## Les modèles
|
||||||
|
|
||||||
Désambiguons `makemigrations` et `migrate` d'abord.
|
Désambiguons `makemigrations` et `migrate` d’abord.
|
||||||
|
|
||||||
|
|
||||||
## L'interface d'administration
|
## L’interface d’administration
|
||||||
|
|
||||||
On a une DB, mais pas encore d'utilisateur admin dedans :
|
On a une DB, mais pas encore d’utilisateur admin dedans :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python manage.py createsuperuser
|
python manage.py createsuperuser
|
||||||
|
@ -224,31 +227,31 @@ python manage.py createsuperuser
|
||||||
|
|
||||||
## Terminé
|
## Terminé
|
||||||
|
|
||||||
On a terminé, on peut essayer maintenant ?
|
On a terminé, on peut essayer maintenant ?
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python manage.py runserver
|
python manage.py runserver
|
||||||
```
|
```
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Leur faire faire ça dans un **autre** shell.
|
Leur faire faire ça dans un **autre** shell.
|
||||||
|
|
||||||
puis les laisser jouer avec l'interface d'admin, créer quelques sites...
|
puis les laisser jouer avec l’interface d’admin, créer quelques sites...
|
||||||
|
|
||||||
|
|
||||||
## L'interface d'administration
|
## L’interface d’administration
|
||||||
|
|
||||||
Les modèles, leurs `fields` ne servent donc pas qu'a l'ORM, cette
|
Les modèles, leurs `fields` ne servent donc pas qu’a l’ORM, cette
|
||||||
interface d'admin nous à demandé une ligne de code.
|
interface d’admin nous a demandé une ligne de code.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Si ce n'est pas déjà fait, leur faire ajouter des `__str__`.
|
Si ce n’est pas déjà fait, leur faire ajouter des `__str__`.
|
||||||
|
|
||||||
|
|
||||||
## Astuce
|
## Astuce
|
||||||
|
|
||||||
On peut passer beaucoup de temps à peaufiner l'interface d'admin,
|
On peut passer beaucoup de temps à peaufiner l’interface d’admin,
|
||||||
repoussez ça après avoir livré une première version.
|
repoussez ça après avoir livré une première version.
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,28 +262,28 @@ repoussez ça après avoir livré une première version.
|
||||||
Créez le modèle `Check` avec les champs `is_up`, `date`, `website`, et
|
Créez le modèle `Check` avec les champs `is_up`, `date`, `website`, et
|
||||||
`message`.
|
`message`.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Pour le champ `website` vous aurez besoin d'un `models.ForeignKey`, RTFM.
|
Pour le champ `website` vous aurez besoin d’un `models.ForeignKey`, RTFM.
|
||||||
|
|
||||||
|
|
||||||
## L'admin
|
## L’admin
|
||||||
|
|
||||||
Ajoutez une interface d'admin pour ce modèle, et ajoutez à la main quelques « *checks* ».
|
Ajoutez une interface d’admin pour ce modèle, et ajoutez à la main quelques « *checks* ».
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Les faire tester ça.
|
Les faire tester ça.
|
||||||
|
|
||||||
|
|
||||||
## Personalisons
|
## Personalisons
|
||||||
|
|
||||||
Dans chaque modèle, un `__str__` aide l'admin à être lisible.
|
Dans chaque modèle, un `__str__` aide l’admin à être lisible.
|
||||||
|
|
||||||
|
|
||||||
## Personalisons
|
## Personalisons
|
||||||
|
|
||||||
Dans `admin.py` on peut préciser les colonnes qu'on veut afficher :
|
Dans `admin.py` on peut préciser les colonnes qu’on veut afficher :
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@admin.register(Website)
|
@admin.register(Website)
|
||||||
|
@ -296,12 +299,12 @@ class CheckAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
# Les URLs & les vues
|
# Les URLs & les vues
|
||||||
|
|
||||||
Changons complètement de sujet : les URLs et des vues.
|
Changons complètement de sujet : les URLs et des vues.
|
||||||
|
|
||||||
|
|
||||||
## Les URLs
|
## Les URLs
|
||||||
|
|
||||||
Dans `project/urls.py` on va se rajouter une URL pour la page d'accueil :
|
Dans `project/urls.py` on va se rajouter une URL pour la page d’accueil :
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from watch import views
|
from watch import views
|
||||||
|
@ -313,9 +316,9 @@ urlpatterns = [
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
C'est un `path`, un chemin, c'est le chemin vide.
|
C’est un `path`, un chemin, c’est le chemin vide.
|
||||||
|
|
||||||
|
|
||||||
## Les URLs
|
## Les URLs
|
||||||
|
@ -341,18 +344,18 @@ from django.urls import include
|
||||||
path("", include("watch.urls")),
|
path("", include("watch.urls")),
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
C'est pratique pour « ancrer » un ensemble de chemin sous un autre
|
C’est pratique pour « ancrer » un ensemble de chemin sous un autre
|
||||||
chemin : pour se faire une hierarchie.
|
chemin : pour se faire une hierarchie.
|
||||||
|
|
||||||
|
|
||||||
## namespaces
|
## namespaces
|
||||||
|
|
||||||
Les espaces de nommage permettent de désambiguer les urls nommées :
|
Les espaces de nommage permettent de désambiguer les urls nommées :
|
||||||
|
|
||||||
`index` est le nom de la page d'accueil de l'interface d'admin de la
|
`index` est le nom de la page d’accueil de l’interface d’admin ou de la
|
||||||
page d'accueil de votre application...
|
page d’accueil de votre application ?
|
||||||
|
|
||||||
|
|
||||||
## namespaces
|
## namespaces
|
||||||
|
@ -364,9 +367,9 @@ Avec les espaces de nommage, on a donc :
|
||||||
|
|
||||||
sans ambiguité.
|
sans ambiguité.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Utiliez-en, c'est bien.
|
Utiliez-en, c’est bien.
|
||||||
|
|
||||||
|
|
||||||
## Les vues
|
## Les vues
|
||||||
|
@ -383,9 +386,9 @@ def index(request):
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
C'est bien mais écrire du HTML dans du Python c'est pas élégant.
|
C’est bien mais écrire du HTML dans du Python c’est pas élégant.
|
||||||
|
|
||||||
|
|
||||||
## Les vues
|
## Les vues
|
||||||
|
@ -425,7 +428,7 @@ Donc dans `watch/templates/watch/index.html` :
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
La création du dossier `templates/` est typiquement quelque chose que
|
La création du dossier `templates/` est typiquement quelque chose que
|
||||||
`runserver` ne voit pas, il faut le redémarrer.
|
`runserver` ne voit pas, il faut le redémarrer.
|
||||||
|
@ -433,7 +436,7 @@ La création du dossier `templates/` est typiquement quelque chose que
|
||||||
|
|
||||||
## Les vues
|
## Les vues
|
||||||
|
|
||||||
Et si on ajoutais de la données provenant de la DB dans le template ?
|
Et si on ajoutait de la donnée provenant de la DB dans le template ?
|
||||||
|
|
||||||
|
|
||||||
## Les vues
|
## Les vues
|
||||||
|
@ -447,18 +450,18 @@ def index(request):
|
||||||
{"websites": Website.objects.all()})
|
{"websites": Website.objects.all()})
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Ne pas oublier les imports…
|
Ne pas oublier les imports…
|
||||||
|
|
||||||
Premier apperçu de l'ORM en passant.
|
Premier apperçu de l’ORM en passant.
|
||||||
|
|
||||||
|
|
||||||
## Les vues
|
## Les vues
|
||||||
|
|
||||||
Digression :
|
Digression :
|
||||||
|
|
||||||
Il existe aussi des vues basées sur des classes, pouvant s'appuyer sur
|
Il existe aussi des vues basées sur des classes, pouvant s’appuyer sur
|
||||||
des modèles.
|
des modèles.
|
||||||
|
|
||||||
|
|
||||||
|
@ -485,7 +488,7 @@ class WebsiteListView(ListView):
|
||||||
|
|
||||||
## Les templates
|
## Les templates
|
||||||
|
|
||||||
Ça fonctionne, mais on ne veux pas répéter l'entête HTML à chaque
|
Ça fonctionne, mais on ne veut pas répéter l’entête HTML à chaque
|
||||||
page…
|
page…
|
||||||
|
|
||||||
|
|
||||||
|
@ -505,14 +508,14 @@ En utilisant `extends`, on peut réutiliser des templates.
|
||||||
python -m pip install django-debug-toolbar
|
python -m pip install django-debug-toolbar
|
||||||
```
|
```
|
||||||
|
|
||||||
L'ajouter dans `settings.py` et `urls.py`.
|
L’ajouter dans `settings.py` et `urls.py`.
|
||||||
|
|
||||||
|
|
||||||
# L'ORM
|
# L’ORM
|
||||||
|
|
||||||
## L'ORM
|
## L’ORM
|
||||||
|
|
||||||
C'est l'occasion de sortir un `python manage.py shell`.
|
C’est l’occasion de sortir un `python manage.py shell`.
|
||||||
|
|
||||||
```pycon
|
```pycon
|
||||||
>>> from watch.models import Website
|
>>> from watch.models import Website
|
||||||
|
@ -524,8 +527,8 @@ Essayer `.all`, `.filter`, `.get`, `.order_by`, et les slices.
|
||||||
|
|
||||||
## Les *Managers*
|
## Les *Managers*
|
||||||
|
|
||||||
Les *managers* représentent une table, il sont accessible via
|
Les *managers* représentent une table, ils sont accessibles via
|
||||||
l'attribut `objects` d'un modèle.
|
l’attribut `objects` d’un modèle.
|
||||||
|
|
||||||
Ses opérations (des méthodes) renvoient des `queryset`s.
|
Ses opérations (des méthodes) renvoient des `queryset`s.
|
||||||
|
|
||||||
|
@ -543,7 +546,7 @@ Les instances de modèles représentent une ligne de la table.
|
||||||
## Les *Queryset*
|
## Les *Queryset*
|
||||||
|
|
||||||
Représentent un ensemble de lignes de la base de donnée. Ils ont les
|
Représentent un ensemble de lignes de la base de donnée. Ils ont les
|
||||||
mêmes méthodes que les *managers* :
|
mêmes méthodes que les *managers* :
|
||||||
|
|
||||||
- filter
|
- filter
|
||||||
- get
|
- get
|
||||||
|
@ -561,8 +564,8 @@ Out[3]: <QuerySet [<Website: mdk.fr>]>
|
||||||
|
|
||||||
## Les *Queryset*
|
## Les *Queryset*
|
||||||
|
|
||||||
Pour ceux qui ont fait du SQL c'est un "lazy select" : c'est un
|
Pour ceux qui ont fait du SQL c’est un "lazy select" : c’est un
|
||||||
`SELECT` qui ne s'éxécutera que si nécessaire.
|
`SELECT` qui ne s’éxécutera que si nécessaire.
|
||||||
|
|
||||||
|
|
||||||
## Les *RelatedManager*
|
## Les *RelatedManager*
|
||||||
|
@ -577,7 +580,7 @@ Out[4]: <QuerySet [<Check: mdk.fr is up>, <Check: mdk.fr is up>]>
|
||||||
|
|
||||||
# Forms
|
# Forms
|
||||||
|
|
||||||
Comme pour l'admin, Django peut utiliser les informations des modèles
|
Comme pour l’admin, Django peut utiliser les informations des modèles
|
||||||
pour vous aider à générer des formulaires.
|
pour vous aider à générer des formulaires.
|
||||||
|
|
||||||
|
|
||||||
|
@ -587,7 +590,7 @@ Créer un formulaire ressemble à créer un modèle, on décrit les champs :
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class WebsiteForm(forms.Form):
|
class WebsiteForm(forms.Form):
|
||||||
host = forms.CharField(label='Website hostname',
|
host = forms.CharField(label="Website hostname",
|
||||||
max_length=512)
|
max_length=512)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -610,7 +613,7 @@ On le donne au template :
|
||||||
|
|
||||||
## Forms
|
## Forms
|
||||||
|
|
||||||
On l'affiche dans le template :
|
On l’affiche dans le template :
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<form action="/" method="post">
|
<form action="/" method="post">
|
||||||
|
@ -639,7 +642,7 @@ class WebsiteForm(forms.ModelForm):
|
||||||
|
|
||||||
## Widgets
|
## Widgets
|
||||||
|
|
||||||
Le rendu HTML d'un champ de formulaire est appelé un `Widget`, il est
|
Le rendu HTML d’un champ de formulaire est appelé un `Widget`, il est
|
||||||
possible de le changer, par exemple si vous préférez un `<input` à un
|
possible de le changer, par exemple si vous préférez un `<input` à un
|
||||||
`<textarea` ou vice-versa.
|
`<textarea` ou vice-versa.
|
||||||
|
|
||||||
|
@ -655,7 +658,7 @@ if request.method == "POST":
|
||||||
Website.objects.create(host=form.cleaned_data["host"])
|
Website.objects.create(host=form.cleaned_data["host"])
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Django peut donc vérifier que les champs non-empty sont bien pas
|
Django peut donc vérifier que les champs non-empty sont bien pas
|
||||||
vides, que les longuers sont respectées, etc…
|
vides, que les longuers sont respectées, etc…
|
||||||
|
@ -663,12 +666,12 @@ vides, que les longuers sont respectées, etc…
|
||||||
|
|
||||||
# Les tests
|
# Les tests
|
||||||
|
|
||||||
Tester c'est douter.
|
Tester c’est douter.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Ou pas. Avoir les tests qui passent avant de pousser, avant de merger
|
Ou pas. Avoir les tests qui passent avant de pousser, avant de merger
|
||||||
une PR, avant de mettre en prod c'est un véritable confort.
|
une PR, avant de mettre en prod c’est un véritable confort.
|
||||||
|
|
||||||
|
|
||||||
## Les fixtures
|
## Les fixtures
|
||||||
|
@ -680,21 +683,22 @@ On appelera ça des « fixtures ».
|
||||||
|
|
||||||
## Les fixtures
|
## Les fixtures
|
||||||
|
|
||||||
Le moyen simple de créer des fixtures est d'utiliser les données que
|
Le moyen simple de créer des fixtures est d’utiliser les données que
|
||||||
vous avez crées via l'admin :
|
vous avez crée via l’admin :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./manage.py dumpdata -o watch/fixtures/initial.json
|
./manage.py dumpdata -o watch/fixtures/initial.json
|
||||||
```
|
```
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Créez le dossier d'abord ;)
|
Créez le dossier d’abord ;)
|
||||||
|
|
||||||
|
|
||||||
## Les fixtures
|
## Les fixtures
|
||||||
|
|
||||||
Profitez-en pour indiquer aux collègues dans le README qu'ils peuvent les charger aussi :
|
Profitez-en pour indiquer aux collègues dans le README qu’ils peuvent
|
||||||
|
les charger aussi :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone …
|
git clone …
|
||||||
|
@ -710,16 +714,16 @@ Par défaut Django utilise la bibliothèque native `unittest`, on
|
||||||
placera les tests de nos applications dans le dossier `tests` ou le
|
placera les tests de nos applications dans le dossier `tests` ou le
|
||||||
fichier `tests.py` des applications.
|
fichier `tests.py` des applications.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Habituellement on dit que le nom du fichier n'a aucune importance, que
|
Habituellement on dit que le nom du fichier n’a aucune importance, que
|
||||||
seul le succès de l'import compte. Ici c'est le contraire, le nom du
|
seul le succès de l’import compte. Ici c’est le contraire, le nom du
|
||||||
fichier doit commencer par `test` pour être trouvé.
|
fichier doit commencer par `test` pour être trouvé.
|
||||||
|
|
||||||
|
|
||||||
## Les tests
|
## Les tests
|
||||||
|
|
||||||
Les tests s'exécutent via :
|
Les tests s’exécutent via :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python manage.py test
|
python manage.py test
|
||||||
|
@ -743,7 +747,7 @@ class WatchTestCase(TestCase):
|
||||||
## Les tests
|
## Les tests
|
||||||
|
|
||||||
Pour vérifier que tout se passe bien `unittest` et `Django` nous
|
Pour vérifier que tout se passe bien `unittest` et `Django` nous
|
||||||
fournissent une collection d'assertions :
|
fournissent une collection d’assertions :
|
||||||
|
|
||||||
- assertTemplateUsed
|
- assertTemplateUsed
|
||||||
- assertRedirects
|
- assertRedirects
|
||||||
|
@ -754,7 +758,7 @@ fournissent une collection d'assertions :
|
||||||
|
|
||||||
## Les tests
|
## Les tests
|
||||||
|
|
||||||
Personnellement habitué à pytest j'abuse de `assert`. Attention, bien
|
Personnellement habitué à pytest j’abuse de `assert`. Attention, bien
|
||||||
que ça fonctionne, les messages ne sont pas aussi lisibles.
|
que ça fonctionne, les messages ne sont pas aussi lisibles.
|
||||||
|
|
||||||
|
|
||||||
|
@ -766,9 +770,9 @@ On a déjà fait une `ForeignKey`, mais il existe aussi :
|
||||||
- ManyToManyField
|
- ManyToManyField
|
||||||
|
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Parler des cas d'usage, et parler de `thrue`.
|
Parler des cas d’usage, et parler de `thrue`.
|
||||||
|
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
@ -784,7 +788,7 @@ Chaque application peut déposer des fichiers dans son dossier `/static/`.
|
||||||
|
|
||||||
## Static assets
|
## Static assets
|
||||||
|
|
||||||
En dev ils seront tous accessibles via l'URL `/static/`.
|
En dev ils seront tous accessibles via l’URL `/static/`.
|
||||||
|
|
||||||
|
|
||||||
## Static assets
|
## Static assets
|
||||||
|
@ -806,34 +810,35 @@ En parlant de prod, comment mettre un Django en prod ?
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Django utilise le protocole `wsgi`, un standard en Python.
|
Django utilise les protocoles `wsgi` (synchrone) et `asgi`
|
||||||
|
(asynchrone), des classiques en Python.
|
||||||
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Attention, `runserver` c'est bien en dev, mais ça n'est pas voué à partir en prod.
|
Attention, `runserver` c’est bien en dev, mais ça n’est pas fait pour la prod.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Sérieusement.
|
Sérieusement.
|
||||||
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
`runserver` c'est un peu comme un groupe éléctrogène :
|
`runserver` c’est un peu comme un groupe éléctrogène :
|
||||||
|
|
||||||
- C'est vrai que ça fonctionne.
|
- C’est vrai que ça fonctionne.
|
||||||
- Ça dépanne quand on est seul dessus, chez soi.
|
- Ça dépanne quand on est seul dessus, chez soi.
|
||||||
- Mais on alimente pas un quartier ou une ville avec.
|
- Mais on alimente pas un quartier ou une ville avec.
|
||||||
|
|
||||||
::: notes
|
notes:
|
||||||
|
|
||||||
Trouver mieux :D
|
Trouver mieux :D
|
||||||
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Nginx et Apache2 gèrent `wsgi`, d'autres serveurs aussi, probablement.
|
Nginx et Apache2 gèrent `wsgi`, d’autres serveurs aussi, probablement.
|
||||||
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
@ -854,7 +859,7 @@ gunicorn -w 16 project.wsgi
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
`gunicorn` est bien derrière un `nginx` qui va s'occuper, entre autre,
|
`gunicorn` est bien derrière un `nginx` qui va s’occuper, entre autres,
|
||||||
de la décapsulation HTTPS, ou de délivrer vos fichiers statiques sans
|
de la décapsulation HTTPS, ou de délivrer vos fichiers statiques sans
|
||||||
passer par Python.
|
passer par Python.
|
||||||
|
|
||||||
|
@ -883,7 +888,7 @@ server {
|
||||||
|
|
||||||
# Bonnes pratiques
|
# Bonnes pratiques
|
||||||
|
|
||||||
Pas de `order_by` / `fiter` / ... dans les vues, rangez ça dans les
|
Pas de `order_by` / `fiter` / … dans les vues, rangez ça dans les
|
||||||
modèles (dans des *managers* personalisés).
|
modèles (dans des *managers* personalisés).
|
||||||
|
|
||||||
Ça permet de nommer et de réutiliser.
|
Ça permet de nommer et de réutiliser.
|
||||||
|
@ -912,7 +917,7 @@ utilisera des applications pour le reste du code.
|
||||||
|
|
||||||
## Bonnes pratiques
|
## Bonnes pratiques
|
||||||
|
|
||||||
On surcharge l'objet `User`, même si on pense ne pas en avoir besoin :
|
On surcharge l’objet `User`, même si on pense ne pas en avoir besoin :
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class User(django.contrib.auth.models.AbstractUser):
|
class User(django.contrib.auth.models.AbstractUser):
|
||||||
|
@ -925,6 +930,12 @@ et :
|
||||||
AUTH_USER_MODEL = ...
|
AUTH_USER_MODEL = ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
notes:
|
||||||
|
|
||||||
|
Enfin, si on est **100% sûrs** que notre application ne sera pas
|
||||||
|
réutilisée dans un contexte où une autre app redéfinit l'object
|
||||||
|
`User`…
|
||||||
|
|
||||||
|
|
||||||
## La configuration de Django
|
## La configuration de Django
|
||||||
|
|
||||||
|
@ -935,4 +946,6 @@ AUTH_USER_MODEL = ...
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
Pour Django on avait : https://ccbv.co.uk/ (Memo: « Classy Class-Based-View »).
|
- La doc officielle.
|
||||||
|
- Pour Django : https://ccbv.co.uk/ (Memo : « Classy Class-Based-View »).
|
||||||
|
- Pour Django Rest Framework : https://www.cdrf.co (Memo : « Classy Django REST Framework »).
|
||||||
|
|
Loading…
Reference in New Issue