Commit 6b9e3cd0 authored by Bonnegent Sebastien's avatar Bonnegent Sebastien
Browse files

cours 7 ok

parent 9b72aa6b
all: cours1.html cours2.html cours3.html cours4.html cours5.html cours6.html
all: cours1.html cours2.html cours3.html cours4.html cours5.html cours6.html cours7.html
%.html: %.md
pandoc -s -t revealjs -V revealjs-url=./reveal.js -V theme=beige -o $@ $<
This diff is collapsed.
---
author:
- Sébastien Bonnegent
title: Django par la pratique 7/7
---
# Départ
## Support
- cours7.html
## Préparation
### L'ancien
~~~
$ git pull
$ cd fwm6
$ pipenv --rm
~~~
### Le nouveau
~~~
$ cd fwm7
$ pipenv install --dev
~~~
## Au programme
- indentation
- les tests
- conf de production
- qcm
# Indentation
## Black
~~~
$ pipenv run black --diff .
$ pipenv run black .
~~~
# Tests
## Lancement
* https://docs.djangoproject.com/fr/2.2/topics/testing/tools/
### Commandes
~~~
$ pipenv run ./manage.py test
System check identified no issues (0 silenced).
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
~~~
## Pytest
* https://pytest-django.readthedocs.io/
* https://fr.wikipedia.org/wiki/Liste_des_codes_HTTP
### Prérequis
~~~
$ pipenv install --dev pytest-django
~~~
## Pytest
### Configuration
~~~
$ cat pytest.ini
[pytest]
DJANGO_SETTINGS_MODULE = conf.settings
python_files = tests.py test_*.py *_tests.py
~~~
### Lancement
~~~
$ pipenv run pytest -v
~~~
## Prérequis
### webui/tests.py
~~~python
# remplacer tous les imports par:
import pytest
from django.urls import reverse
from django.core.exceptions import ValidationError
from webui.models import Parefeu, Regle, Service
~~~
## Accès anonyme
### webui/tests.py
~~~python
def test_home_anon(client):
response = client.get(reverse('home'))
# redirection vers la page de login
assert response.status_code == 302
~~~
> $ pipenv run pytest -v
## Accès admin
### webui/tests.py
~~~python
def test_an_admin_view(admin_client):
response = admin_client.get('/admin/')
assert response.status_code == 200
~~~
> $ pipenv run pytest -v
## URLs simples
### webui/tests.py
~~~python
def test_urls_simple(admin_client):
response = admin_client.get(reverse('services'))
assert response.status_code == 200
response = admin_client.get(reverse('ports'))
assert response.status_code == 200
response = admin_client.get(reverse('parefeux'))
assert response.status_code == 200
response = admin_client.get(reverse('contact'))
assert response.status_code == 200
~~~
> $ pipenv run pytest -v
## URLS simple v2
### webui/tests.py
~~~python
def test_urls_simple_v2(admin_client):
urls = ['services', 'ports', 'parefeux',
'contact']
for url in urls:
response = admin_client.get(reverse(url))
assert response.status_code == 200
~~~
## Données initiales
### webui/tests.py
~~~python
@pytest.fixture
def parefeu1(admin_user):
get_or_create = Parefeu.objects.get_or_create
(parefeu, created) = get_or_create(nom="parefeu1",
admin=admin_user)
return parefeu
~~~
## Utilisation
### webui/tests.py
~~~python
def test_url_parefeu(admin_client, parefeu1):
kwargs = {"pk": parefeu1.id}
url = reverse("parefeu-detail", kwargs=kwargs)
response = admin_client.get(url)
assert response.status_code == 200
~~~
## à faire #1
### webui/tests.py
* créé parefeu2 et parefeu3
* test_nb_regles_parefeu(admin_user, parefeu1)
* on crée plusieurs règles
* Parefeu.nombre_de_regles() doit donner le bon nombre
## test_nb_regles_parefeu
### webui/tests.py
~~~python
def test_nb_regles_parefeu(admin_user, parefeu1):
assert parefeu1.nombre_de_regles() == 0
svc = Service(nom="service1")
svc.save()
for i in range(5):
regle = Regle(parefeu=parefeu1)
regle.save()
regle.services.add(svc)
assert parefeu1.nombre_de_regles() == 5
~~~
## à faire #2
### test_nb_regles_modele
* comme précédent mais pour les règles sur un modèle
* parefeu2 est le modele de parefeu1
* parefeu1 n'a pas de règles
* parefeu2 a des règles
* nb_regles doit retourner nb_regle de parefeu1 + parefeu2
## Modèle
* un parefeu ne peut être son modèle
* https://docs.djangoproject.com/en/2.2/ref/forms/validation/
### webui/tests.py
~~~python
def test_parefeu_niv1(admin_client, parefeu1):
parefeu1.modele = parefeu1
try:
parefeu1.full_clean()
except ValidationError:
assert True
else:
pytest.fail("le parefeu peut se référencer en tant que modèle")
~~~
## Modèle
### webui/models.py
~~~python
from django.core.exceptions import ValidationError
class Parefeu(AvecNom):
def clean(self):
super(Parefeu, self).clean()
if self.modele and self.modele == self:
raise ValidationError({"modele": "Interdépendance parefeu/modele"})
~~~
## à faire #3
### test_parefeu_niv2
* un parefeu ne peut être le modèle de son modèle
* écrire le test
* parefeu1.modele = parefeu2
* parefeu2.modele = parefeu1
* raise ValidationError
* modifier Parefeu.clean()
## à faire #4
### test_parefeu_niv3
* un parefeu ne peut être le modèle du modèle du modèle ... de son modèle
* écrire le test
* parefeu1.modele = parefeu2
* parefeu2.modele = parefeu3
* parefeu3.modele = parefeu1
* modifier Parefeu.clean()
* définir une profondeur maximum de parcours (12)
* raise ValidationError
## Parallélisation
### Prérequis
~~~
$ pipenv install --dev pytest-xdist
~~~
### Lancement
~~~
$ pipenv run pytest -n 4
~~~
## Performance
~~~
$ pipenv run pytest
10 passed in 1.70s
$ pipenv run pytest -n 4
10 passed in 1.98s
~~~
# Production
## Configuration
* ne pas utiliser le runserver !
~~~
$ pipenv run ./manage.py collectstatic
$ pipenv run ./manage.py check --deploy
~~~
### pipenv
* export PIPENV_VENV_IN_PROJECT="yes"
* répertoire .venv
## Apache/httpd
### django.conf
~~~
ServerSignature off
ServerTokens prod
WSGIPythonPath "/opt/fwm/.venv"
<VirtualHost fwm.insa-rouen.fr:80>
Redirect permanent / https://fwm.insa-rouen.fr/
</VirtualHost>
<VirtualHost fwm.insa-rouen.fr:443>
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/fwm.crt
SSLCertificateKeyFile /etc/httpd/ssl/fwm.key
SSLCertificateChainFile /etc/httpd/ssl/ca.crt
DocumentRoot /var/www/html/
Alias /favicon.ico /opt/fwm/static/favicon.ico
Alias /static/ /opt/fwm/static/
<Directory /opt/fwm/>
Require all granted
</Directory>
WSGIDaemonProcess fwm python-path=/opt/fwm:/opt/fwm/.venv/lib/python3.6/site-packages processes=2 threads=15 display-name=%{GROUP}
WSGIProcessGroup fwm
WSGIScriptAlias / /opt/fwm/conf/wsgi.py
<Directory /opt/fwm/conf>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
</VirtualHost>
~~~
# QCM !
......@@ -6,7 +6,7 @@ verify_ssl = true
[dev-packages]
[packages]
django = "*"
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
......
......@@ -6,7 +6,7 @@ verify_ssl = true
[dev-packages]
[packages]
django = "*"
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
......
......@@ -6,7 +6,7 @@ verify_ssl = true
[dev-packages]
[packages]
django = "*"
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
django-bootstrap-static = "*"
......
......@@ -6,7 +6,7 @@ verify_ssl = true
[dev-packages]
[packages]
django = "*"
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
django-bootstrap-static = "*"
......
......@@ -7,7 +7,7 @@ verify_ssl = true
werkzeug = "*"
[packages]
django = "*"
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
django-bootstrap-static = "*"
......
......@@ -7,7 +7,7 @@ verify_ssl = true
werkzeug = "*"
[packages]
django = "*"
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
django-bootstrap-static = "*"
......
No preview for this file type
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
werkzeug = "*"
black = "==18.6b4"
pytest-django = "*"
pytest-xdist = "*"
[packages]
django = "==2.2.7"
django-extensions = "*"
ipython = "*"
django-bootstrap-static = "*"
fontawesome = "*"
[requires]
python_version = "3.6"
{
"_meta": {
"hash": {
"sha256": "43bb0a7433630ffc6d745e61eaa699a271dc864030a8f08521f30c4fabbe1e6e"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"backcall": {
"hashes": [
"sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4",
"sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"
],
"version": "==0.1.0"
},
"decorator": {
"hashes": [
"sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce",
"sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"
],
"version": "==4.4.1"
},
"django": {
"hashes": [
"sha256:16040e1288c6c9f68c6da2fe75ebde83c0a158f6f5d54f4c5177b0c1478c5b86",
"sha256:89c2007ca4fa5b351a51a279eccff298520783b713bf28efb89dfb81c80ea49b"
],
"index": "pypi",
"version": "==2.2.7"
},
"django-bootstrap-static": {
"hashes": [
"sha256:d9f1f9f7561efb9a73cd80a380d26628047805540ddb12002a453cebb6a74fed",
"sha256:fb8516189604b783f24a76e582ccbd90254ba81499dcf01e04e9016666760e8c"
],
"index": "pypi",
"version": "==4.2.1"
},
"django-extensions": {
"hashes": [
"sha256:a9db7c56a556d244184f589f2437b4228de86ee45e5ebb837fb20c6d54e95ea5",
"sha256:b58320d3fe3d6ae7d1d8e38959713fa92272f4921e662d689058d942a5b444f7"
],
"index": "pypi",
"version": "==2.2.5"
},
"fontawesome": {
"hashes": [
"sha256:1b5e8f2ed12a74b88aef6f404ff770af425324041bc5620523a802d5406595b8",
"sha256:642d74da5f4726bb2c8f035a2f4a98fdc4294d213a291994ee0b3d845166f9e8"
],
"index": "pypi",
"version": "==5.10.1.post1"
},
"ipython": {
"hashes": [
"sha256:c66c7e27239855828a764b1e8fc72c24a6f4498a2637572094a78c5551fb9d51",
"sha256:f186b01b36609e0c5d0de27c7ef8e80c990c70478f8c880863004b3489a9030e"
],
"index": "pypi",
"version": "==7.10.1"
},
"ipython-genutils": {
"hashes": [
"sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8",
"sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"
],
"version": "==0.2.0"
},
"jedi": {
"hashes": [
"sha256:786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27",
"sha256:ba859c74fa3c966a22f2aeebe1b74ee27e2a462f56d3f5f7ca4a59af61bfe42e"
],
"version": "==0.15.1"
},
"parso": {
"hashes": [
"sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc",
"sha256:666b0ee4a7a1220f65d367617f2cd3ffddff3e205f3f16a0284df30e774c2a9c"
],
"version": "==0.5.1"
},
"pexpect": {
"hashes": [
"sha256:2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1",
"sha256:9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"
],
"markers": "sys_platform != 'win32'",
"version": "==4.7.0"
},
"pickleshare": {
"hashes": [
"sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca",
"sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
],
"version": "==0.7.5"
},
"prompt-toolkit": {
"hashes": [
"sha256:0278d2f51b5ceba6ea8da39f76d15684e84c996b325475f6e5720edc584326a7",
"sha256:63daee79aa8366c8f1c637f1a4876b890da5fc92a19ebd2f7080ebacb901e990"
],
"version": "==3.0.2"
},
"ptyprocess": {
"hashes": [
"sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0",
"sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"
],
"version": "==0.6.0"
},
"pygments": {
"hashes": [
"sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b",
"sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"
],
"version": "==2.5.2"
},
"pytz": {
"hashes": [
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
],
"version": "==2019.3"
},
"six": {
"hashes": [
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
"version": "==1.13.0"
},
"sqlparse": {
"hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
"sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873"
],
"version": "==0.3.0"
},
"traitlets": {
"hashes": [
"sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44",
"sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"
],
"version": "==4.3.3"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"version": "==0.1.7"
}
},
"develop": {
"apipkg": {
"hashes": [
"sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6",
"sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"
],
"version": "==1.5"
},
"appdirs": {
"hashes": [
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
],
"version": "==1.4.3"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.3.0"
},
"black": {
"hashes": [
"sha256:22158b89c1a6b4eb333a1e65e791a3f8b998cf3b11ae094adb2570f31f769a44",
"sha256:4b475bbd528acce094c503a3d2dbc2d05a4075f6d0ef7d9e7514518e14cc5191"
],
"index": "pypi",
"version": "==18.6b4"
},
"click": {
"hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
],
"version": "==7.0"
},
"execnet": {
"hashes": [
"sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50",
"sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"
],
"version": "==1.7.1"
},
"importlib-metadata": {
"hashes": [
"sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45",
"sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"
],
"markers": "python_version < '3.8'",
"version": "==1.3.0"
},
"more-itertools": {
"hashes": [
"sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d",
"sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564"
],
"version": "==8.0.2"
},
"packaging": {
"hashes": [
"sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47",
"sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"
],
"version": "==19.2"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"version": "==0.13.1"
},