Commit 0542fafa authored by Bonnegent Sebastien's avatar Bonnegent Sebastien
Browse files

cours 2 à jour

parent 60643088
all: cours1.html cours2.html
all: cours1.html cours2.html cours3.html
%.html: %.md
pandoc -s -t revealjs -V revealjs-url=./reveal.js -V theme=beige -o $@ $<
......@@ -12,17 +12,15 @@ séance.
* mise en place du projet
* mise en place de l'application
* migration
* 1er classe (Port)
* 1er modèle (Port)
* shell
## Cours 2
* frontend
- administration
- serveur de développement
- urls, templates, vues
* interface d'administration
* modèles avec relations (Service, Groupe)
## Cours 3
* frontend: manipulation des objets
* suite des modèles avec relations (Regle, Parefeu)
* logging
* messages
......
......@@ -144,7 +144,7 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<h2>L’environnement pipenv<a href="#/fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a></h2>
<pre><code>$ git clone https://gitlab.insa-rouen.fr/bonnegent/cours_django.git
$ cd cours_django
$ mkdir fwm
$ mkdir fwm1
$ cd !$
$ pipenv --python 3.6
$ pipenv install django django-extensions ipython</code></pre>
......@@ -362,17 +362,11 @@ $ pipenv run ./manage.py migrate
<a class="sourceLine" id="cb24-15" title="15">In [<span class="dv">5</span>]: Port.objects.<span class="bu">all</span>().delete()</a></code></pre></div>
</section><section id="webuimodels.py-3" class="slide level2">
<h2>webui/models.py</h2>
<p>Faire les classes suivantes.</p>
<p>Faire la classe suivante</p>
<h3 id="adresse">Adresse</h3>
<pre><code>- nom: chaine de caractères (25)
- ip: une adresse IP
- masque: le masque réseau (défaut: 32)</code></pre>
<h3 id="groupe">Groupe</h3>
<pre><code>- nom: chaine de caractères (25)
- adresses: une liste d&#39;Adresse</code></pre>
<h3 id="service">Service</h3>
<pre><code>- nom: chaine de caractères (25)
- ports: une liste de ports</code></pre>
</section></section>
<section><section id="documentation" class="title-slide slide level1"><h1>Documentation</h1></section><section id="django-1" class="slide level2">
<h2>Django</h2>
......
......@@ -44,7 +44,7 @@ title: Django par la pratique 1/7
~~~
$ git clone https://gitlab.insa-rouen.fr/bonnegent/cours_django.git
$ cd cours_django
$ mkdir fwm
$ mkdir fwm1
$ cd !$
$ pipenv --python 3.6
$ pipenv install django django-extensions ipython
......@@ -330,18 +330,12 @@ In [5]: Port.objects.all().delete()
~~~
## webui/models.py
Faire les classes suivantes.
Faire la classe suivante
### 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
......
This diff is collapsed.
......@@ -4,17 +4,24 @@ author:
title: Django par la pratique 2/7
---
# Départ
## Support de cours
Attention au remplacement de fwm !
## Fichiers
- support: cours2.html
### L'ancien
~~~
$ git pull
$ git checkout cours_2
$ cd fwm1
$ pipenv --rm
~~~
### Le nouveau
~~~
$ cd fwm2
$ pipenv install
~~~
## Au programme
- l'interface d'administration
- les modèles
- les modèles avec relations (Service, Groupe)
# Administration
## Serveur de développement
......@@ -27,7 +34,8 @@ $ pipenv run ./manage.py runserver
=> http://127.0.0.1:8000
## webui/admin.py
## À modifier
### webui/admin.py
~~~python
from django.contrib import admin
from .models import Port
......@@ -90,7 +98,7 @@ Créer les ports suivants:
- 389/tcp
- 443/tcp
## Affichage
## à modifier
### webui/admin.py
~~~python
class PortAdmin(admin.ModelAdmin):
......@@ -100,7 +108,34 @@ class PortAdmin(admin.ModelAdmin):
admin.site.register(Port, PortAdmin)
~~~
## à faire
- Adresse dans la partie administration
- afficher les colonnes: nom, ip et masque
- créer les Adresses suivantes:
- localhost 127.0.0.0/8
- www.insa-rouen.fr 193.49.10.214/32
- dsi.insa-rouen.fr 193.49.10.146/32
# Service
## Factorisation
- Adresse et Service ont un attribut **nom**
- => création d'une classe abstraite
## à modifier
### 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
~~~
## ManyToMany
- relation type 0 à n vers une autre classe
- manipulation via add, remove
......@@ -108,7 +143,8 @@ admin.site.register(Port, PortAdmin)
- pas de save()
- cas de Service vers Port
## webui/models.py
## à modifier
### webui/models.py
~~~python
class Service(AvecNom):
"""Un service regroupe un ensemble de ports.
......@@ -119,6 +155,11 @@ class Service(AvecNom):
ports = models.ManyToManyField(Port)
~~~
~~~
$ pipenv run ./manage.py makemigrations
$ pipenv run ./manage.py migrate
~~~
## Administration
- Ajouter Service dans l'interface d'administration
......@@ -183,10 +224,12 @@ Out[35]: <QuerySet [<Service: web>]>
~~~
## Administration
### Améliorations
- afficher la liste des ports
- ordre de tri par nom
- champs de recherche
## à modifier
### webui/models.py
~~~python
class Service(models.Model):
......@@ -208,123 +251,21 @@ class ServiceAdmin(admin.ModelAdmin):
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
# Groupe
## À faire
### webui/models.py
- nom
- adresses: de 0 à N Adresse
## À faire
### 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
- on_delete [^on_delete]: comportement lors de la suppression de la cible
- CASCADE: suppression aussi de l'instance
- SET_NULL: valeur nulle
- DO_NOTHING
- ...
[^on_delete]: https://docs.djangoproject.com/fr/2.2/ref/models/fields/
## webui/models.py
~~~python
SENS = (("i", "Input"), ("f", "Forward"), ("o", "Output"))
class Regle(models.Model):
priorite = models.PositiveIntegerField(default=0)
groupe = models.ForeignKey(Groupe, blank=True, null=True,
on_delete=models.CASCADE)
services = models.ManyToManyField(Service)
interface = models.CharField(default="", max_length=25,
blank=True)
actif = models.BooleanField(default=True)
sens = models.CharField(max_length=1, choices=SENS,
default="i")
parefeu = models.ForeignKey(Parefeu, on_delete=models.CASCADE)
~~~
# Parefeu
## À faire
### webui/models.py
- nom
- modification: date/heure de dernière modification
- modele: héritage d'un Parefeu
- admin: administrateur du parefeu (User)
## webui/models.py
~~~python
from django.contrib.auth.models import User
class Parefeu(AvecNom):
# mise à jour auto à chaque save()
modification = models.DateTimeField(auto_now=True)
modele = models.ForeignKey('Parefeu', null=True, blank=True,
on_delete=models.CASCADE)
admin = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta(object):
verbose_name_plural = "parefeux"
~~~
## webui/models.py
~~~python
def nombre_de_regles(self):
nb = self.regle_set.count()
if self.modele:
nb += self.modele.nombre_de_regles()
return nb
~~~
## À faire
### webui/admin.py
- interface d'administration
- colonnes:
- nom
- modele
- nombre_de_regles (modele + parefeu)
- modification
## webui/admin.py
~~~python
class ParefeuAdmin(admin.ModelAdmin):
list_display = ("nom", "modele",
"nombre_de_regles", "modification")
date_hierarchy = 'modification'
~~~
### Administration
- ajouter un groupe **Serveurs Web** contenant
- dsi.insa-rouen.fr
- www.insa-rouen.fr
# FIN !
\ No newline at end of file
# Fin !
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="author" content="Sébastien Bonnegent">
<title>Django par la pratique 3/7</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="./reveal.js/css/reveal.css">
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
{ position: relative; left: -4em; }
pre.numberSource a.sourceLine::before
{ content: attr(title);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; pointer-events: all; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="./reveal.js/css/theme/beige.css" id="theme">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? './reveal.js/css/print/pdf.css' : './reveal.js/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="./reveal.js/lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section id="title-slide">
<h1 class="title">Django par la pratique 3/7</h1>
<p class="author">Sébastien Bonnegent</p>
</section>
<section><section id="départ" class="title-slide slide level1"><h1>Départ</h1></section><section id="fichiers" class="slide level2">
<h2>Fichiers</h2>
<ul>
<li>support: cours3.html</li>
</ul>
<h3 id="lancien">L’ancien</h3>
<pre><code>$ cd fwm2
$ pipenv --rm</code></pre>
<h3 id="le-nouveau">Le nouveau</h3>
<pre><code>$ cd fwm3
$ pipenv install</code></pre>
</section><section id="au-programme" class="slide level2">
<h2>Au programme</h2>
<ul>
<li>suite des modèles avec relations
<ul>
<li>Regle</li>
<li>Parefeu</li>
</ul></li>
</ul>
</section></section>
<section><section id="règle" class="title-slide slide level1"><h1>Règle</h1></section><section id="attributs" class="slide level2">
<h2>Attributs</h2>
<ul>
<li>priorite: un entier positif</li>
<li>groupe: un groupe d’Adresse</li>
<li>services: une liste de Service</li>
<li>interface: une chaine de caractères (25)</li>
<li>actif: un booléen</li>
<li>sens: un élément de la liste Input, Forward, Output</li>
<li>parefeu: un Parefeu ‘modèle’</li>
</ul>
</section><section id="foreignkey" class="slide level2">
<h2>ForeignKey</h2>
<ul>
<li>cas de Groupe et Parefeu</li>
<li>lien vers une seule instance d’une autre classe</li>
<li>chargé par l’ORM (regle.groupe.nom)</li>
<li>null: valeur nulle base de données</li>
<li>blank: valeur nulle formulaire</li>
<li>on_delete <a href="#/fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a>: comportement lors de la suppression de la cible
<ul>
<li>CASCADE: suppression aussi de l’instance</li>
<li>SET_NULL: valeur nulle</li>
<li>DO_NOTHING</li>
<li></li>
</ul></li>
</ul>
</section><section id="webuimodels.py" class="slide level2">
<h2>webui/models.py</h2>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb3-1" title="1">SENS <span class="op">=</span> ((<span class="st">&quot;i&quot;</span>, <span class="st">&quot;Input&quot;</span>), (<span class="st">&quot;f&quot;</span>, <span class="st">&quot;Forward&quot;</span>), (<span class="st">&quot;o&quot;</span>, <span class="st">&quot;Output&quot;</span>))</a>
<a class="sourceLine" id="cb3-2" title="2"></a>
<a class="sourceLine" id="cb3-3" title="3"><span class="kw">class</span> Regle(models.Model):</a>
<a class="sourceLine" id="cb3-4" title="4"> priorite <span class="op">=</span> models.PositiveIntegerField(default<span class="op">=</span><span class="dv">0</span>)</a>
<a class="sourceLine" id="cb3-5" title="5"> groupe <span class="op">=</span> models.ForeignKey(Groupe, blank<span class="op">=</span><span class="va">True</span>, null<span class="op">=</span><span class="va">True</span>,</a>
<a class="sourceLine" id="cb3-6" title="6"> on_delete<span class="op">=</span>models.CASCADE)</a>
<a class="sourceLine" id="cb3-7" title="7"> services <span class="op">=</span> models.ManyToManyField(Service)</a>
<a class="sourceLine" id="cb3-8" title="8"> interface <span class="op">=</span> models.CharField(default<span class="op">=</span><span class="st">&quot;&quot;</span>, max_length<span class="op">=</span><span class="dv">25</span>,</a>
<a class="sourceLine" id="cb3-9" title="9"> blank<span class="op">=</span><span class="va">True</span>)</a>
<a class="sourceLine" id="cb3-10" title="10"> actif <span class="op">=</span> models.BooleanField(default<span class="op">=</span><span class="va">True</span>)</a>
<a class="sourceLine" id="cb3-11" title="11"> sens <span class="op">=</span> models.CharField(max_length<span class="op">=</span><span class="dv">1</span>, choices<span class="op">=</span>SENS,</a>
<a class="sourceLine" id="cb3-12" title="12"> default<span class="op">=</span><span class="st">&quot;i&quot;</span>)</a>
<a class="sourceLine" id="cb3-13" title="13"> parefeu <span class="op">=</span> models.ForeignKey(Parefeu, on_delete<span class="op">=</span>models.CASCADE)</a></code></pre></div>
</section></section>
<section><section id="parefeu" class="title-slide slide level1"><h1>Parefeu</h1></section><section id="à-faire" class="slide level2">
<h2>À faire</h2>
<h3 id="webuimodels.py-1">webui/models.py</h3>
<ul>
<li>nom</li>
<li>modification: date/heure de dernière modification</li>
<li>modele: héritage d’un Parefeu</li>
<li>admin: administrateur du parefeu (User)</li>
</ul>
</section><section id="webuimodels.py-2" class="slide level2">
<h2>webui/models.py</h2>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb4-1" title="1"><span class="im">from</span> django.contrib.auth.models <span class="im">import</span> User</a>
<a class="sourceLine" id="cb4-2" title="2"><span class="kw">class</span> Parefeu(AvecNom):</a>
<a class="sourceLine" id="cb4-3" title="3"> <span class="co"># mise à jour auto à chaque save()</span></a>
<a class="sourceLine" id="cb4-4" title="4"> modification <span class="op">=</span> models.DateTimeField(auto_now<span class="op">=</span><span class="va">True</span>)</a>
<a class="sourceLine" id="cb4-5" title="5"> modele <span class="op">=</span> models.ForeignKey(<span class="st">&#39;Parefeu&#39;</span>, null<span class="op">=</span><span class="va">True</span>, blank<span class="op">=</span><span class="va">True</span>,</a>
<a class="sourceLine" id="cb4-6" title="6"> on_delete<span class="op">=</span>models.CASCADE)</a>
<a class="sourceLine" id="cb4-7" title="7"> admin <span class="op">=</span> models.ForeignKey(User, on_delete<span class="op">=</span>models.CASCADE)</a>
<a class="sourceLine" id="cb4-8" title="8"></a>
<a class="sourceLine" id="cb4-9" title="9"> <span class="kw">class</span> Meta(<span class="bu">object</span>):</a>
<a class="sourceLine" id="cb4-10" title="10"> verbose_name_plural <span class="op">=</span> <span class="st">&quot;parefeux&quot;</span></a></code></pre></div>
</section><section id="webuimodels.py-3" class="slide level2">
<h2>webui/models.py</h2>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb5-1" title="1"> <span class="kw">def</span> nombre_de_regles(<span class="va">self</span>):</a>
<a class="sourceLine" id="cb5-2" title="2"> nb <span class="op">=</span> <span class="va">self</span>.regle_set.count()</a>
<a class="sourceLine" id="cb5-3" title="3"> <span class="cf">if</span> <span class="va">self</span>.modele:</a>
<a class="sourceLine" id="cb5-4" title="4"> nb <span class="op">+=</span> <span class="va">self</span>.modele.nombre_de_regles()</a>
<a class="sourceLine" id="cb5-5" title="5"> <span class="cf">return</span> nb</a></code></pre></div>
</section><section id="à-faire-1" class="slide level2">
<h2>À faire</h2>
<h3 id="webuiadmin.py">webui/admin.py</h3>
<ul>
<li>interface d’administration</li>
<li>colonnes:
<ul>
<li>nom</li>
<li>modele</li>
<li>nombre_de_regles (modele + parefeu)</li>
<li>modification</li>
</ul></li>
</ul>
</section><section id="webuiadmin.py-1" class="slide level2">
<h2>webui/admin.py</h2>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb6-1" title="1"><span class="kw">class</span> ParefeuAdmin(admin.ModelAdmin):</a>
<a class="sourceLine" id="cb6-2" title="2"> list_display <span class="op">=</span> (<span class="st">&quot;nom&quot;</span>, <span class="st">&quot;modele&quot;</span>,</a>
<a class="sourceLine" id="cb6-3" title="3"> <span class="st">&quot;nombre_de_regles&quot;</span>, <span class="st">&quot;modification&quot;</span>)</a>
<a class="sourceLine" id="cb6-4" title="4"> date_hierarchy <span class="op">=</span> <span class="st">&#39;modification&#39;</span></a></code></pre></div>
</section></section>
<section><section id="fin" class="title-slide slide level1"><h1>FIN !</h1></section></section>
<section class="footnotes">
<hr />
<ol>
<li id="fn1"><p>https://docs.djangoproject.com/fr/2.2/ref/models/fields/<a href="#/fnref1" class="footnote-back"></a></p></li>
</ol>
</section>
</div>
</div>
<script src="./reveal.js/lib/js/head.min.js"></script>
<script src="./reveal.js/js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
// Push each slide change to the browser history
history: true,
// Optional reveal.js plugins
dependencies: [
{ src: './reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: './reveal.js/plugin/zoom-js/zoom.js', async: true },
{ src: './reveal.js/plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>
---
author:
- Sébastien Bonnegent
title: Django par la pratique 3/7
---
# Départ
## Fichiers
- support: cours3.html
### L'ancien
~~~
$ cd fwm2
$ pipenv --rm
~~~
### Le nouveau
~~~
$ cd fwm3
$ pipenv install
~~~
## Au programme
- suite des modèles avec relations
- Regle
- Parefeu
# 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
- on_delete [^on_delete]: comportement lors de la suppression de la cible
- CASCADE: suppression aussi de l'instance