Commit 60643088 authored by Bonnegent Sebastien's avatar Bonnegent Sebastien
Browse files

préparation du regroupement

parent 86c88ce5
all: cours1.html cours2.html
%.html: %.md
pandoc -s -t revealjs -V revealjs-url=./reveal.js -V theme=beige -o $@ $<
......@@ -49,7 +49,19 @@ séance.
~~~
$ git clone https://gitlab.insa-rouen.fr/bonnegent/cours_django/
$ cd cours_django
$ git checkout cours_1
~~~
Il faut ouvrir le fichier **cours.html** dans votre navigateur favori.
Il faut ouvrir le fichier **cours1.html** dans votre navigateur favori.
# Liste des fichiers
* cours?.html : le support de cours
* cours?.md : la source du support de cours
* fwm? : le répertoire du projet django correspondant au cours
* make : regénère les fichiers html
# Outils utilisés
* vim
* pandoc
* revealjs
This diff is collapsed.
---
author:
- Sébastien Bonnegent
title: Django par la pratique 1/7
---
# Django
## Qu'est ce que c'est ?
> The web framework for perfectionists with deadlines.[^dj]
[^dj]: \tiny https://www.djangoproject.com/
- framework web python de haut niveau
- rapide à mettre en place
- flexible
## Avantages
- factorisation du code
- interface d'administration automatique
- architecture MVC (Model-Template-View)
- ORM: postgresql, mysql, sqlite, oracle, ...
- serveur de développement intégré
- gestion des migrations
- ...
## Inconvénients
- ?
## Utiliser par
- disqus
- dropbox (storage)
- instagram
- mozilla
- open stack
- pinterest
- spotify
- youtube
- ...
# Prérequis
## L'environnement pipenv[^pipenv]
~~~
$ git clone https://gitlab.insa-rouen.fr/bonnegent/cours_django.git
$ cd cours_django
$ mkdir fwm
$ cd !$
$ pipenv --python 3.6
$ pipenv install django django-extensions ipython
~~~
[^pipenv]: https://gitlab.insa-rouen.fr/bonnegent/cours_django/wikis/pipenv
## Projet ou application ?
> Une application est une application Web qui fait
> quelque chose – par exemple un système de blog,
> une base de données publique ou une application de
> sondage.
> Un projet est un ensemble de réglages et d’applications
> pour un site Web particulier. Un projet peut contenir
> plusieurs applications.
> Une application peut apparaître dans plusieurs projets.[^ted]
[^ted]: \tiny https://docs.djangoproject.com/fr/2.2/intro/tutorial01/
## Création du projet
~~~
$ pipenv run django-admin startproject conf .
~~~
![](images/tree-conf.png)
## Création d'une application
~~~
$ pipenv run django-admin startapp webui
~~~
![](images/tree-webui.png)
## Activation de l'application
### conf/settings.py
~~~python
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'webui',
'django_extensions',
]
~~~
## Configuration
### conf/settings.py
~~~python
DEBUG = True
ALLOWED_HOSTS = []
ROOT_URLCONF = 'conf.urls'
LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'Europe/Paris'
SECRET_KEY = 'Une_clef_secrete_et_longue!'
~~~
### Pour générer une nouvelle clé secrête
~~~
$ pipenv run ./manage.py generate_secret_key
f#wgrz$@#wh@*x5)_+(*$$^aw(c!q#a4)c0230bwp!iy
~~~
## Gestion des migrations
### Création (si nécessaire)
~~~
$ pipenv run ./manage.py makemigrations
~~~
### Application
~~~
$ pipenv run ./manage.py migrate
~~~
![](images/tree-migrate-initial.png)
## Quelques commandes utiles
~~~
$ pipenv run ./manage.py shell
$ # shell avec chargement automatique des classes
$ pipenv run ./manage.py shell_plus
~~~
~~~
$ pipenv run ./manage.py createsuperuser
~~~
### Serveur de développement
~~~
$ pipenv run ./manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
September 28, 2017 - 13:29:48
Django version 1.11, using settings 'conf.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
~~~
# Notre projet
## But
Gestion des règles des parefeux à travers une interface web. On pourra
créer des groupes de ports / services et gérer plusieurs parefeux différents.
## Diagramme des classes
![](images/diagramme_classe.png)
Note: pas de clé primaire !
# À vous de jouer !
## Ports
- protocole: any (défaut), tcp, udp, icmp
- début: entier positif, 0 par défaut
- fin: entier positif, 0 par défaut
## webui/models.py
~~~python
PROTO = (('a', 'any'), ('t', 'tcp'),
('u', 'udp'), ('i', 'icmp'))
class Port(models.Model):
protocole = models.CharField(max_length=1,
choices=PROTO,
default='a')
debut = models.PositiveIntegerField(default=0)
fin = models.PositiveIntegerField(default=0)
~~~
## Appliquer les modifications
~~~
$ pipenv run ./manage.py makemigrations
Migrations for 'webui':
webui/migrations/0001_initial.py
- Create model Port
$ pipenv run ./manage.py migrate
...
~~~
## Contenu d'une migration
~~~
$ cat webui/migrations/0001_initial.py
~~~
~~~python
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [ ]
operations = [
migrations.CreateModel(
name='Port',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('protocole', models.CharField(choices=[('a', 'any'), ('t', 'tcp'), ('u', 'udp'), ('i', 'icmp')], default='a', max_length=1)),
('debut', models.PositiveIntegerField(default=0)),
('fin', models.PositiveIntegerField(default=0)),
],
),
]
~~~
## Shell django
### pipenv run ./manage.py shell
~~~python
>>> from webui.models import Port
>>> p = Port()
>>> p.protocole
'a'
>>> p.get_protocole_display()
'any'
>>> p.debut
0
>>> p.fin
0
>>> p.debut = 22
>>> p.save()
>>> p
<Port: Port object (1)>
~~~
## webui/models.py
Modifier l'affichage des instances.
~~~python
class Port(models.Model):
def __str__(self):
ports = f"{self.debut}"
if self.debut < self.fin:
ports += f"-{self.fin}"
return f"{ports}({self.get_protocole_display()})"
~~~
## Shell plus
### pipenv run ./manage.py shell_plus
~~~python
>>> p = Port(debut=80, protocole="tcp", fin=88)
>>> p
<Port: 80-88(tcp)>
>>> p.save()
>>> p = Port(debut=80, protocole="tcp")
>>> p
<Port: 80(tcp)>
>>> p.save()
>>> Port(protocole="tcp", debut=25).save()
>>> Port.objects.all()
<QuerySet [<Port: 22(any)>, <Port: 80-88(tcp)>,
<Port: 80(tcp)>, <Port: 25(tcp)>]>
~~~
## webui/models.py
Modifier l'ordre des instances.
~~~python
class Port(models.Model):
class Meta(object):
ordering = ('debut', 'protocole', 'fin')
~~~
### shell
~~~python
>>> Port.objects.all()
<QuerySet [<Port: 22(any)>, <Port: 25(tcp)>,
<Port: 80(tcp)>, <Port: 80-88(tcp)>]>
~~~
## Récupération
~~~python
>>> Port.objects.get(debut=22)
<Port: 22(any)>
>>> Port.objects.get(debut=80)
webui.models.Port.MultipleObjectsReturned: get() returned more than one Port
~~~
### Création si besoin
~~~python
port, flag = Port.objects.get_or_create(debut=25)
~~~
## Sélection
~~~python
In [1]: Port.objects.filter(debut=80)
Out[1]: <QuerySet [<Port: 80(tcp)>, <Port: 80-88(tcp)>]>
In [2]: Port.objects.filter(debut=80).count()
Out[2]: 2
In [3]: Port.objects.filter(debut=80)[1]
Out[3]: <Port: 80-88(tcp)>
In [4]: Port.objects.filter(debut__gt=20)
Out[4]: <QuerySet [<Port: 22(tcp)>, <Port: 25(tcp)>,
<Port: 80(tcp)>, <Port: 80-88(tcp)>]>
In [5]: Port.objects.filter(debut__gt=20).filter(debut__lte=25)
Out[5]: <QuerySet [<Port: 22(tcp)>, <Port: 25(tcp)>]>
In [6]: Port.objects.filter(debut__gt=20, debut__lte=25)
Out[6]: <QuerySet [<Port: 22(tcp)>, <Port: 25(tcp)>]>
~~~
## Suppression
~~~python
In [1]: Port.objects.all()
Out[1]: <QuerySet [<Port: 22(any)>, <Port: 25(tcp)>,
<Port: 80(tcp)>, <Port: 80-88(tcp)>]>
In [2]: Port.objects.get(fin=88)
Out[2]: <Port: 80-88(tcp)>
In [3]: Port.objects.get(fin=88).delete()
Out[3]: (1, {'webui.Port': 1})
In [4]: Port.objects.filter(debut__gt=22,
debut__lte=25).delete()
Out[4]: (1, {'webui.Port': 1})
In [5]: Port.objects.all().delete()
~~~
## webui/models.py
Faire les classes suivantes.
### Adresse
- nom: chaine de caractères (25)
- ip: une adresse IP
- masque: le masque réseau (défaut: 32)
### Groupe
- nom: chaine de caractères (25)
- adresses: une liste d'Adresse
### Service
- nom: chaine de caractères (25)
- ports: une liste de ports
# Documentation
## Django
- https://docs.djangoproject.com/fr/
- partie modèle
- https://docs.djangoproject.com/fr/2.2/intro/tutorial01/
- tutoriel officiel
This diff is collapsed.
---
author:
- Sébastien Bonnegent
title: Django par la pratique 2/7
---
# Départ
## Support de cours
Attention au remplacement de fwm !
~~~
$ git pull
$ git checkout cours_2
~~~
## Au programme
- l'interface d'administration
- les modèles
# Administration
## Serveur de développement
~~~
$ pipenv run ./manage.py runserver
~~~
- débugger facilement
- permet de tester rapidement le projet
=> http://127.0.0.1:8000
## webui/admin.py
~~~python
from django.contrib import admin
from .models import Port
admin.site.register(Port)
~~~
## accéder à l'admin
~~~
$ pipenv run ./manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
November 10, 2019 - 17:53:48
Django version 2.2.6, using settings 'conf.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
~~~
=> http://127.0.0.1:8000/admin
## problème
Il faut un utilisateur ! :)
![](images/admin_login.png)
## créer un utilisateur
~~~
$ pipenv run ./manage.py createsuperuser
Nom d'utilisateur (leave blank to use 'bonnegent'): admin
Adresse électronique: ad@min.fr
Password:
Password (again):
Le mot de passe est trop semblable au champ « nom d'utilisateur ».
Ce mot de passe est trop court. Il doit contenir au minimum 8 caractères.
Ce mot de passe est trop courant.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
~~~
## ./manage.py shell_plus
~~~python
In [1]: User.objects.all()
Out[1]: <QuerySet [<User: admin>]>
In [2]: u = User.objects.get(username='admin')
In [3]: u.is_superuser
Out[3]: True
In [4]: u.is_staff
Out[4]: True
~~~
## Administration
Créer les ports suivants:
- 53/udp
- 389/tcp
- 443/tcp
## Affichage
### webui/admin.py
~~~python
class PortAdmin(admin.ModelAdmin):
list_display = ('debut', 'fin', 'protocole')
admin.site.register(Port, PortAdmin)
~~~
# Service
## ManyToMany
- relation type 0 à n vers une autre classe
- manipulation via add, remove
- liste triée par défaut
- pas de save()
- cas de Service vers Port
## webui/models.py
~~~python
class Service(AvecNom):
"""Un service regroupe un ensemble de ports.
:param ports: une liste de Ports
"""
nom = models.CharField(default='', max_length=25)
ports = models.ManyToManyField(Port)
~~~
## Administration
- Ajouter Service dans l'interface d'administration
- Ajouter les services suivants:
- ssh: 22/tcp
- ldap: 389/tcp
- web: 80/tcp, 443/tcp
- dns: 53/udp
## shell_plus
~~~python
web = Service.objects.get(nom="web")
p22 = Port.objects.get(debut=22)
p80 = Port.objects.get(debut=80)
p443 = Port.objects.get(debut=443)
~~~
## Manipulation
~~~python
In [5]: web.ports.add(p80, p443)
In [6]: web.ports.all() # pas de double !
Out[6]: <QuerySet [<Port: 80(tcp)>, <Port: 443(tcp)>]>
In [7]: web.ports.add(p22)
In [8]: web.ports.all()
Out[8]: <QuerySet [<Port: 22(tcp)>, <Port: 80(tcp)>, <Port: 443(tcp)>]>
In [9]: web.ports.remove(p22)
In [10]: web.ports.all()
Out[10]: <QuerySet [<Port: 80(tcp)>, <Port: 443(tcp)>]>
~~~
## Affectation
~~~python
In [17]: web.ports.set([p80, p22])
In [18]: web.ports.all()
Out[18]: <QuerySet [<Port: 22(tcp)>, <Port: 80(tcp)>]>
In [19]: web.ports.set([p80, p443])
~~~
## Filtrage
~~~python
In [23]: filtre = Service.objects.filter
In [24]: filtre(ports__debut__gt=80)
Out[24]: <QuerySet [<Service: ldap>, <Service: web>]>
In [25]: filtre(ports__debut__gt=22)
Out[25]: <QuerySet [<Service: dns>, <Service: ldap>,
<Service: web>, <Service: web>]>
In [26]: filtre(ports__debut__gt=22).distinct()
Out[26]: <QuerySet [<Service: dns>, <Service: ldap>, <Service: web>]>
~~~
## Relation inverse
~~~python
In [34]: Port.objects.filter(service=web)
Out[34]: <QuerySet [<Port: 80(tcp)>, <Port: 443(tcp)>]>
In [35]: p80.service_set.all()
Out[35]: <QuerySet [<Service: web>]>
~~~
## Administration
- afficher la liste des ports
- ordre de tri par nom
- champs de recherche
### webui/models.py
~~~python
class Service(models.Model):
class Meta(object):
ordering = ('nom', )
def liste_des_ports(self):
return ", ".join([str(p)
for p in self.ports.all()])
~~~
## webui/admin.py
~~~python
from .models import Service
class ServiceAdmin(admin.ModelAdmin):
list_display = ('nom', 'liste_des_ports')
search_fields = ('nom', 'ports__debut')
admin.site.register(Service, ServiceAdmin)
~~~
# Modèles
## Factorisation
- Adresse et Service ont un attribut **nom**
- modifier les classes pour utiliser cette classe abstraite
## webui/models.py
~~~python
class AvecNom(models.Model):
"""Classe abstraite pour les classes ayant un nom"""
nom = models.CharField(default='', max_length=25)
class Meta(object):
abstract = True
ordering = ('nom', )
def __str__(self):
return self.nom
~~~
## Groupe
À faire
### webui/models.py
- nom
- adresses: de 0 à N Adresse
### webui/admin.py
- interface d'administration
- colonne 'liste_des_adresses'
# Règle
## Attributs
- priorite: un entier positif
- groupe: un groupe d'Adresse
- services: une liste de Service
- interface: une chaine de caractères (25)
- actif: un booléen
- sens: un élément de la liste Input, Forward, Output
- parefeu: un Parefeu 'modèle'
## ForeignKey
- cas de Groupe et Parefeu
- lien vers une seule instance d'une autre classe
- chargé par l'ORM (regle.groupe.nom)
- null: valeur nulle base de données
- blank: valeur nulle formulaire