davin.baragiotta 31/08/2012 02:17:07
---------------------------------- DÉBUT ATELIER DJANGO FRONTEND ------------------------------
{{{#!python
Bonjour à tous 31/08/2012 02:17:11
https://wiki.auf.org/wikiteki/Projet/SemaineTech/2012/Ateliers/DjangoFrontend 31/08/2012 02:17:42
l'atelier Django Frontend est une suite logique de l'atelier Django Architecture d'un projet et backend 31/08/2012 02:18:03
mais peut être suivi indépendamment 31/08/2012 02:18:13
il est annoncé pour Django 1.4 et Django 1.1.1 31/08/2012 02:18:25
mais ce sera plus simple pour Django 1.1.1 car tout le matériel est prêt 31/08/2012 02:18:39
(1.4 devrit être prêt pour prochaine édition de cet atelier... plus tard en journée) 31/08/2012 02:18:58
la page de l,atelier.... le contenu de la présentation est ici : 31/08/2012 02:19:12
https://wiki.auf.org/wikiteki/Ateliers/Django/Backend/Support 31/08/2012 02:19:23
ach non! 31/08/2012 02:19:37
ici plutôt : 31/08/2012 02:19:42
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support 31/08/2012 02:19:55
INTRODUCTION 31/08/2012 02:20:00
Notre objectif aujourd'hui 31/08/2012 02:20:11
est de présenter les données qu'on sait maintenant gérer dans l,admin 31/08/2012 02:20:23
les présentées au public dans des interfaces publiques 31/08/2012 02:20:32
la documentation Django est au même endroit qu'hier 31/08/2012 02:20:58
je sais que ceux qui suivent étaient là hier... 31/08/2012 02:21:11
maintenant, le contenu couvert ici équivaut au contenu de la 3e partie du tutoriel officiel 31/08/2012 02:21:36
je passe l'environnement technique... si il y a des nouveaux, vous manifester dans tech svp... Tri est modérateur 31/08/2012 02:22:00
RAPPELS ET AMORCE DU PROJET 31/08/2012 02:22:11
on veut pas repartir de zéro... 31/08/2012 02:22:19
c'est à dire qu'on veut pas 31/08/2012 02:22:29
recréer un projet, une app... faire toute la config... créer des modèles 31/08/2012 02:22:39
donc je vous ai donné des sources pour qu'on parte tous avec les mêmes bases 31/08/2012 02:23:01
Django 1.1.1 31/08/2012 02:23:04
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support%3Faction%3DAttachFile%26do%3Dget%26target%3Dcarto_1_1_backend_final.tar.gz 31/08/2012 02:23:12
je vous laisse télécharger 31/08/2012 02:23:20
l'intérêt de cette archive 31/08/2012 02:23:28
c'est qu'elle correspondant au code complet final de l'atelier Backend 31/08/2012 02:23:50
on a même un jeu de données rigolo que j'ai saisi 31/08/2012 02:24:00
ah, pour ceux que ça intéresse 31/08/2012 02:24:07
l'ensemble des manips de l'atelier Backend et Frontend 31/08/2012 02:24:22
se trouve suivies dans git... 31/08/2012 02:24:28
Tri 31/08/2012 02:24:30
Cette page n'existe pas encore.!
davin.baragiotta 31/08/2012 02:24:33
dans mon dépôt perso
ok minute... je charge l'archive 31/08/2012 02:24:56
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support?action=AttachFile&do=get&target=carto_1_1_backend_final.tar.gz 31/08/2012 02:25:41
Tri 31/08/2012 02:26:10
c'est bon!
davin.baragiotta 31/08/2012 02:26:34
super...
je vous laisse dépaqueter 31/08/2012 02:26:46
faire un petit :
python manage.py runserver 31/08/2012 02:27:03
regarde un coup dans l'admin pour voir les données : 31/08/2012 02:27:13
http://127.0.0.1:8000/admin 31/08/2012 02:27:26
questions? 31/08/2012 02:28:51
tout marche? 31/08/2012 02:28:54
Tri 31/08/2012 02:29:33
[09:28:44] Khone: Question: Les codes dans JP est pareil que hier (pour tous ce qui est fini) ?
davin.baragiotta 31/08/2012 02:29:56
JP ?
le code dans l,archive est pareil et plus que hier 31/08/2012 02:30:13
j'ai ajouté 2-3 trucs dans models.py et admin.py 31/08/2012 02:30:27
si vous avez votre code d'hier : pas de probl... 31/08/2012 02:30:36
Tri 31/08/2012 02:30:40
[09:30:38] Khone: Pièce-Joint (JP)
davin.baragiotta 31/08/2012 02:30:42
avez juste des données....
c'est nul de faire des listes d'un élément dans les interfaces 31/08/2012 02:31:03
ok.... je considère qu'on est tous ensemble dans le nouveau code de l,archive en Django 1.1.1 31/08/2012 02:31:36
Tri 31/08/2012 02:31:44
ca marche pour Huy et khuon
davin.baragiotta 31/08/2012 02:32:19
c'est important qu'on soit tous ok
tous : je présente dans la doc 3 options pour les sources : 31/08/2012 02:32:36
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support#Amorce_du_projet 31/08/2012 02:32:41
télécharger l'archive est une approche 31/08/2012 02:32:52
ok on part pour vrai 31/08/2012 02:34:49
FRONTEND 31/08/2012 02:34:59
l'idée d'un frontend vs backend 31/08/2012 02:35:10
c'est un peu comme une boutique et son arrière boutique 31/08/2012 02:35:21
phouvichit.xongmixay a rejoint le salon 02:35
davin.baragiotta 31/08/2012 02:35:48
y'a des trucs qu'on veut pas offir au client : backend
le reste = frontend 31/08/2012 02:35:51
nous on code les interfaces publiques 31/08/2012 02:35:58
vous vous rappelez du schéma de dev web en Django? 31/08/2012 02:36:11
http://montrealpython.org/r/attachments/13/web-development.jpg 31/08/2012 02:36:20
là... on va passer dans tous les fichiers : 31/08/2012 02:36:32
dans cet ordre : 31/08/2012 02:36:36
urls.py 31/08/2012 02:36:37
views.py 31/08/2012 02:36:40
templates 31/08/2012 02:36:42
on va commecner par se créer une page d'accueil 31/08/2012 02:36:55
pas con, hein? 31/08/2012 02:36:58
la requête pour la page d,accueil = le root de notre nom de domaine 31/08/2012 02:37:18
/ 31/08/2012 02:37:22
en localhost, ça donne : 31/08/2012 02:37:33
http://127.0.0.1:8000 31/08/2012 02:37:42
ou 31/08/2012 02:37:45
http://127.0.0.1:8000/ 31/08/2012 02:37:50
tapez cette URL dans notre navigateur 31/08/2012 02:38:05
python manage.py runserver doit rouler 31/08/2012 02:38:14
vous devez avoir une erreur 31/08/2012 02:38:38
shafeek.sumser 31/08/2012 02:38:44
oui
davin.baragiotta est en Django 1.4.... je suis pas des masses 02:38
davin.baragiotta 31/08/2012 02:38:58
normal
tran.xuan.huy a quitté la salle 02:39
davin.baragiotta 31/08/2012 02:39:16
ça doit dire que y,a pas d'URL pour ça
Tri a quitté la salle 02:39
davin.baragiotta 31/08/2012 02:39:50
donc on va coder l'urls qui gère le /
dans views.py 31/08/2012 02:39:54
non... dans urls.py 31/08/2012 02:40:07
éditer le fichier 31/08/2012 02:40:13
on va ajouter un ligne 31/08/2012 02:40:19
url(r'^$', 'carto_1_1.views.home', name='home'), 31/08/2012 02:40:29
Tri a rejoint le salon 02:40
davin.baragiotta 31/08/2012 02:41:03
carto_1_1 = facultatif... et s'appelle comme ça pour ceux ayant télécahrger les sources... c'est le nom du projet
ça se lit comme suit : 31/08/2012 02:41:07
Tri a quitté la salle 02:41
tran.xuan.huy a rejoint le salon 02:41
davin.baragiotta 31/08/2012 02:41:39
on édite le fichier suivant : carto_1_1/urls.py
Tri a rejoint le salon 02:41
davin.baragiotta 31/08/2012 02:41:49
pas dans l'app annuaire...
direct dans projet 31/08/2012 02:41:52
donc ça se lit comme suit : 31/08/2012 02:42:00
"voici un nouveau pattern d'URL : si après le nom de domain, ça commence avec (^) et finit ($) avec rien.... 31/08/2012 02:42:52
alors c'est la *fonction* dans carto_1_1.views.home qu'il faut exécuter 31/08/2012 02:43:17
et par ailleurs... le nom de ce pattern d'URL c'Est "home" 31/08/2012 02:43:30
voilà pour l'inteprétation de cette ligne 31/08/2012 02:43:38
maintenant... l'erreur devrait être différente au refresh 31/08/2012 02:43:49
shafeek.sumser 31/08/2012 02:43:55
oui
davin.baragiotta 31/08/2012 02:44:09
il doit dire "hey.... j'ai pas de views correspondant"
donc on va créer ce fichier views.py 31/08/2012 02:44:18
créez un fichier : carto_1_1/views.py 31/08/2012 02:44:32
PAS dans annuaire 31/08/2012 02:44:36
(fichier vide) 31/08/2012 02:44:47
petit mot sur génie logiciel... 31/08/2012 02:45:07
une app contient du code qui est logiquement peut dépendant du reste 31/08/2012 02:45:23
cohérence forte (dans l'app)... couplage faible (entre l'app et le reste) 31/08/2012 02:45:40
la page d'accueil... c'est la page du projet... 31/08/2012 02:45:49
pas de l'app... 31/08/2012 02:45:52
donc on la met ailleur que dans l'app 31/08/2012 02:45:59
donc on édite views.py : 31/08/2012 02:46:09
from django.shortcuts import render_to_response from django.template import Context, RequestContext def home(request): c = {} return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) 31/08/2012 02:46:20
grrrrrrrrrr.... 31/08/2012 02:46:23
indenté 31/08/2012 02:46:28
# -*- encoding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import Context, RequestContext
from carto_1_1.annuaire.models import Etablissement
def home(request):
"""Page d'accueil du site"""
c = {
}
return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) 31/08/2012 02:46:43
copiez 31/08/2012 02:46:52
on en parle dans une seconde... 31/08/2012 02:46:57
ça c'est le code de base... qui se trouve dans la doc... 31/08/2012 02:47:20
c'est le bout pénible qu'on retient pas par coeur... 31/08/2012 02:47:29
et qu'on copie colle toujours 31/08/2012 02:47:34
aussi 31/08/2012 02:47:37
khone-cc 31/08/2012 02:47:38
Question de Khuon et Huy:
(09:45:23) khuon.tiv: Could not import carto_1_1.views. Error was: No module named views
davin.baragiotta 31/08/2012 02:47:55
khuon.tiv: justement... on crée ce views pour enelver l'erreur
n'oubliez pas : 31/08/2012 02:48:12
le but d'une app web c'est de construire une réponse à la requête HTTP 31/08/2012 02:48:32
là notre requête c'est GET / 31/08/2012 02:48:39
c,est pas seulement urls.py qui fait la réponse 31/08/2012 02:48:51
urls.py a les règles pour dispatcher le travail 31/08/2012 02:49:01
ça dit "ah? tu veux /... alors le boulot doit se faire là :" 31/08/2012 02:49:13
le là en question.... on a dit que c'était dans views.py sur la racine du projet... 31/08/2012 02:49:31
Tri 31/08/2012 02:49:33
Davin, je demande a Khone de faire la moderation, je dois regler un pb de courriel au BAP
davin.baragiotta 31/08/2012 02:49:40
... mais il n'existe pas encore
Tri ok 31/08/2012 02:49:42
donc on crée views.py à la racine. 31/08/2012 02:49:55
relisons le code qu'on vient de copier dans views... qu'on comprenne ce qu'on fait 31/08/2012 02:50:10
# -*- encoding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import Context, RequestContext
from carto_1_1.annuaire.models import Etablissement
def home(request):
"""Page d'accueil du site"""
c = {
}
return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) 31/08/2012 02:50:13
les imports... (from... import) 31/08/2012 02:50:22
c'est toujours pour utiliser ce qu'on importe plus bas 31/08/2012 02:50:30
on import donc render_to_responses et Context et RequestContext 31/08/2012 02:50:46
c'est utilisé plus bas 31/08/2012 02:50:50
idem pour Etablissement... 31/08/2012 02:50:57
def home() 31/08/2012 02:51:01
Tri a quitté la salle 02:51
davin.baragiotta 31/08/2012 02:51:09
def = fonction en Python
tran.xuan.huy a quitté la salle 02:51
davin.baragiotta 31/08/2012 02:51:25
c'est la fonction qui a la responsabilité de créer la réponse à la requête HTTP
home() prend en paramètre... jsutement la requête :
request 31/08/2012 02:51:42
def home(request): 31/08/2012 02:51:50
Tri a rejoint le salon 02:52
davin.baragiotta 31/08/2012 02:52:18
une fonction peut retourner un résultat... ici, ce sera notre réponse Http
return ... 31/08/2012 02:52:25
Tri a quitté la salle 02:52
davin.baragiotta 31/08/2012 02:53:07
render_to_response... son boulot et justement de faire le rendu d'un template (HTML)... pour construire la réponse finale à la requête
Tri a rejoint le salon 02:53
tran.xuan.huy a rejoint le salon 02:53
davin.baragiotta 31/08/2012 02:53:34
si on regarde les param de render_to_response()
"home.html"... c'est le template HTML qu'on veut "rendre".... c'est à dire interpréter et résoudre pour faire un rendu sous forme de réponse 31/08/2012 02:54:11
ritesh.dhora a rejoint le salon 02:54
davin.baragiotta 31/08/2012 02:54:34
Context et le RequestContext... c'est des variables qui sont passées au template
on y revient 31/08/2012 02:54:42
bon! 31/08/2012 02:54:44
alors on a donc codé views.py : avec la focntion appelée par urls.py 31/08/2012 02:54:58
faites refresh... vous devriez avoir une dernière erreur 31/08/2012 02:55:10
des questions sur urls.py et views.py? 31/08/2012 02:55:19
khone-cc 31/08/2012 02:56:17
(09:56:50) Khone: Question: Dans le param de render_to_response(), on peut réponse plusieurs pages par home.html, contact.html ...?
davin.baragiotta 31/08/2012 02:56:23
non
khone-cc 31/08/2012 02:56:38
pas autre question, continue ..
davin.baragiotta 31/08/2012 02:56:38
ça n'a pas de sens : on fait une réponse à une requête
si tu veux "switcher"... soit du le fait dans l'urls.py (bonne approhce) 31/08/2012 02:56:54
ou tu switche plus haut dans la focntion.... 31/08/2012 02:57:03
mais chaque render_to_response() = 1 seul template 31/08/2012 02:57:13
maintenant votre erreur devrait plus être "hey on n'a pas de views" 31/08/2012 02:57:28
mais plutôt "hey, on n'a pas le template home.html!" 31/08/2012 02:57:40
donc on va le créer 31/08/2012 02:57:47
par convention 31/08/2012 02:57:57
dans les projets django 31/08/2012 02:58:01
on met les templates dans un répertoire nommé... 31/08/2012 02:58:10
templates! 31/08/2012 02:58:13
créez un répertoire templates à la racine du projet 31/08/2012 02:58:25
dans ce répertoire... créez home.html 31/08/2012 02:58:50
mettez quelque chose de sympa dans home.html 31/08/2012 02:59:18
genre :
J'aime Django
31/08/2012 02:59:35
en principe, un refresh devrait rendre le tout ok 31/08/2012 02:59:51
mais en principe seulement 31/08/2012 02:59:59
faut configurer Django pour qu'il sache où sont les templates 31/08/2012 03:00:11
lui dire la convention qu'on suit quoi! 31/08/2012 03:00:18
ouvrez settings.py 31/08/2012 03:00:32
onveut éditer TEMPLATE_DIRS 31/08/2012 03:00:43
lisez un peu le message en commentaire... 31/08/2012 03:00:51
khone-cc 31/08/2012 03:01:03
Question: (10:01:29) shafeek.sumser: faut modifier le settings.py pour activer le templates?
davin.baragiotta 31/08/2012 03:01:23
oui
essaie refresh sans avoir modifé settings.py 31/08/2012 03:01:33
toujours erreur, non? 31/08/2012 03:01:41
khone-cc 31/08/2012 03:01:56
Oui; tjs erreur ..
davin.baragiotta 31/08/2012 03:01:59
bon l'idée... c'est que Django sache le path exact pour aller chercher les templates... 31/08/2012 03:02:21
bosco.boukone a rejoint le salon 03:02
davin.baragiotta 31/08/2012 03:02:39
absolute paths
comment faire pour coder sans qu'on ait à modifer la config quand on déploiera sur serveur??? 31/08/2012 03:02:59
là on travaille dans notre home/user/... 31/08/2012 03:03:08
(ou ailleurs) 31/08/2012 03:03:12
mais on sait pas où code sera déployé sur serveur 31/08/2012 03:03:21
bref 31/08/2012 03:03:22
faut chemin absolu qu,on va construire dynamiquement : 31/08/2012 03:03:40
shafeek.sumser 31/08/2012 03:03:44
template_dirs à modifier aussi ?
davin.baragiotta 31/08/2012 03:04:12
TEMPLATE_DIRS est à modifier... la seule config qu'on a tenté de modifié aujourd'hui
(hier on a fait des modifs à settings) 31/08/2012 03:04:22
donc 31/08/2012 03:04:25
ajoutez :
import os 31/08/2012 03:04:30
Tri a quitté la salle 03:04
davin.baragiotta 31/08/2012 03:04:33
en haut de fihier
os = un module de standard library 31/08/2012 03:04:47
permet de manipuler le système de fichier 31/08/2012 03:04:54
ajouté ceci dans template dir : 31/08/2012 03:05:02
Tri a rejoint le salon 03:05
davin.baragiotta 31/08/2012 03:05:07
os.path.join(os.path.dirname(__file__), "templates"),
ça donne ceci au final : 31/08/2012 03:05:13
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "Cwww/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.join(os.path.dirname(__file__), "templates"),
) 31/08/2012 03:05:19
lisons.... 31/08/2012 03:05:22
__file__ = le fichier en cours... donc settings.py 31/08/2012 03:05:39
on dit donc "prend le répertoire parent de settings.py ey join le à "templates") 31/08/2012 03:06:07
khone-cc 31/08/2012 03:06:17
Question: (10:06:34) nguyen.le.duc.huy: Q: import os dans setting.py?
davin.baragiotta 31/08/2012 03:06:32
pas le répertoire... en fait c'est le path absolu sur le système
oui dans settings 31/08/2012 03:06:35
ça se résouds comme suit : /home/user/projets/carto_1_1/ 31/08/2012 03:07:00
pour moi 31/08/2012 03:07:03
c'est la façon de créer dynamiquement un path absolu vers un fichier... relativement à settings.py 31/08/2012 03:07:32
bref... si vous comprendez pas : pas grave, ça marche 31/08/2012 03:07:43
nguyen.le.duc.huy 31/08/2012 03:07:54
ls
davin.baragiotta 31/08/2012 03:07:59
?
maintenant, ne faisant un refresh... 31/08/2012 03:08:08
vous devriez voir votre code HTML dans le navigateur ; 31/08/2012 03:08:25
plus d'erreur.... 31/08/2012 03:08:28
exact? 31/08/2012 03:08:39
ben bravo! vous avez une application web qui répond à une requête HTTP par une réponse HTTP : retourne du HTML 31/08/2012 03:09:45
31/08/2012 03:09:46
mmais bon... 31/08/2012 03:09:58
c'est pas très sexy comme traitement 31/08/2012 03:10:09
je vais vous montrer un peu l'intérêt d'un views.py 31/08/2012 03:10:21
on veut pas traiter juste des fihciers statiques... comme on vient de le faire avec notre home.html 31/08/2012 03:10:39
on veut du dynamique 31/08/2012 03:10:43
une page qui va afficher des variables 31/08/2012 03:10:55
31/08/2012 03:10:59
dans views.py 31/08/2012 03:11:05
focntion home 31/08/2012 03:11:08
on va "passer" une variable au template 31/08/2012 03:11:17
codez : dans le corps de la fcontion : 31/08/2012 03:11:57
def home(request):
"""Page d'accueil du site"""
variable = "Davin"
c = {
'var':variable,
}
return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) 31/08/2012 03:12:39
lisons 31/08/2012 03:12:46
variable = 'Davin' 31/08/2012 03:12:52
c'est un string Python 31/08/2012 03:12:57
pas très dynamique car "hardcodé" dans la fonction 31/08/2012 03:13:10
codé en dur... 31/08/2012 03:13:13
(ensuite on va interroger la DB... on y arrive ) 31/08/2012 03:13:24
c = dictionnaire Python 31/08/2012 03:13:36
avec { } 31/08/2012 03:13:41
'var' = une des clés du dictionnaires (la seule déclarée) 31/08/2012 03:13:58
on voit que cette clé prend la valeur de variable 31/08/2012 03:14:11
'var':variable, 31/08/2012 03:14:17
finalement... 31/08/2012 03:14:22
le dictionnaire "c" est passé à Context 31/08/2012 03:14:39
qui a pour but de rendre accessible toutes les clés du dictionnaire 31/08/2012 03:14:56
comme des "variables" pour le template 31/08/2012 03:15:06
en clair : 'var' devient donc accessible dans le template 31/08/2012 03:15:17
faisons la preuve 31/08/2012 03:15:20
ouvrons le template 31/08/2012 03:15:23
édition : templates/home.html 31/08/2012 03:15:38
ajoutez un peu n'importe où "{{ var }}" 31/08/2012 03:15:57
la syntaxe dans un template... ce n'est plus du Python 31/08/2012 03:16:09
c'est un langage de template 31/08/2012 03:16:15
Django a son propre langage de template 31/08/2012 03:16:22
mais il existe des lanages indépendants dans l'univers Python, comme "mako" 31/08/2012 03:16:41
bref : Django est monolithique... il a ses propres trucs... et tout est documenté sur son site : pratique 31/08/2012 03:17:02
revenons à nos moutons 31/08/2012 03:17:08
donc le langage de template de Django nous permet d'afficher la valeur d'une variable passée au template : 31/08/2012 03:17:31
la syntexe c'est 31/08/2012 03:17:35
{{ nom_variable }} 31/08/2012 03:17:44
le nom de la variable, c'est la clé du dictionnaire... 31/08/2012 03:17:57
donc ici c'est {{ var }} 31/08/2012 03:18:05
refresh : vous devriez voir le string codé dans la fonction 31/08/2012 03:18:17
dans mon exemple : 'Davin' 31/08/2012 03:18:24
ça marche? 31/08/2012 03:18:27
des questions? 31/08/2012 03:18:30
on a un pépin avec un participant, on débogue dans tech 31/08/2012 03:22:30
thierry.tsitoara a quitté la salle 03:28
davin.baragiotta 31/08/2012 03:29:57
hourra!
tout est réglé! 31/08/2012 03:30:00
on avait édité des fichiers sans les sauvegarder... et aussi 31/08/2012 03:30:12
on avait fait une erreur dans la clé du dictionnaire (nom de variable) 31/08/2012 03:30:34
bon 31/08/2012 03:30:35
maintenant passons aux choses sérieuses 31/08/2012 03:30:42
car afficher du code "hardcodé"... codé en dur... c'est nul 31/08/2012 03:30:56
on va interrogé la base de donnéess 31/08/2012 03:31:03
attachez-vous... là on va sérieusement devenir des développeurs d'applications web 31/08/2012 03:31:23
plan de match : 31/08/2012 03:31:31
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support 31/08/2012 03:31:38
ORM : exploration interactive 31/08/2012 03:31:55
vous avez suivi l'atelier Python.... 31/08/2012 03:32:10
vous avez une idée de la puissance du langage et des imports qui viennent 31/08/2012 03:32:25
qui viennent avec 31/08/2012 03:32:38
dans Django 31/08/2012 03:32:49
le vrai code Python vit dans les views.py 31/08/2012 03:33:08
c'est à dire que le reste, c'est plutôt de la config 31/08/2012 03:33:19
bien sûr que urls.py c'est du Python 31/08/2012 03:33:27
mais on suit les convention de Django pour configurer nos patterns 31/08/2012 03:33:40
dans les views.py 31/08/2012 03:33:45
dans ses focntions on fait ce qu'on veut 31/08/2012 03:33:52
une page... son contenu... ça se construit comme on veut 31/08/2012 03:34:01
et cette consturction c'est dans views.py 31/08/2012 03:34:10
le rôle de views.py 31/08/2012 03:34:13
c'est de fournir les variables au template 31/08/2012 03:34:25
donc faire tout le traitement logique sur les données et "parler" à l'utilisateur dans le template 31/08/2012 03:34:44
notre projet... c,est celui d'un annuaire de l'AUF 31/08/2012 03:35:01
il est temps de coder autre chose que des hello world 31/08/2012 03:35:11
31/08/2012 03:35:12
on veut, dans nos views, appeler les données de la base de données 31/08/2012 03:35:33
les stocker dans des variables 31/08/2012 03:35:40
et les passer au template 31/08/2012 03:35:44
donc 31/08/2012 03:35:45
tout ceci se fait avec l'ORM de Django 31/08/2012 03:35:54
(il existe en Python d'autres ORM... comme SQLAlchemy, plus puissant d'ailleurs... mais on aime Django car il est monolithique) 31/08/2012 03:36:23
Django a son ORM 31/08/2012 03:36:30
la doc d'utilisation de l'ORM est ici : 31/08/2012 03:36:39
olivier.larcheveque a rejoint le salon 03:36
davin.baragiotta 31/08/2012 03:36:47
https://docs.djangoproject.com/en/1.4//topics/db/queries/
maintenant 31/08/2012 03:36:52
on va vu que la meilleure façon d'expérimenter en Python 31/08/2012 03:37:10
c'est dans l'interpréteur 31/08/2012 03:37:17
on va donc expérimenter l'ORM dans l'interpréteur 31/08/2012 03:37:32
pour lancer l'interpréteur avec tout l'environnement de Django 31/08/2012 03:37:48
(settings, par exemple) 31/08/2012 03:37:55
faut faire la commande suivante : 31/08/2012 03:38:02
python manage.py shell 31/08/2012 03:38:11
demandez à Django de lancez le shell dans le contexte de notre projet 31/08/2012 03:38:33
khone-cc 31/08/2012 03:38:37
(10:39:09) Khone: Question: est-ce qu'on peut utiliser: ipython manage.py shell ?
davin.baragiotta 31/08/2012 03:38:42
non
python = pour exécuter manage.py 31/08/2012 03:38:58
ensuite... manage.py exécute la commande shell 31/08/2012 03:39:09
et dans ce cas... il utilise ton shell préféré 31/08/2012 03:39:19
si tu as iPython d'installé 31/08/2012 03:39:26
c'est lui qui doit être lancé par : 31/08/2012 03:39:34
python manage.py shell 31/08/2012 03:39:40
exact? 31/08/2012 03:39:44
khone-cc 31/08/2012 03:39:48
ok
davin.baragiotta 31/08/2012 03:39:59
ok
super 31/08/2012 03:40:06
nous allons donc utilisez l'ORM 31/08/2012 03:40:15
dernier mot de théorie : 31/08/2012 03:40:21
ORM = object relational mapping 31/08/2012 03:40:29
c'est à dire 31/08/2012 03:40:31
association entre la notion d'objet et la notion de base de données relationnelle 31/08/2012 03:40:49
la DB relational = carto.db 31/08/2012 03:40:57
la notion d'objet = models.py 31/08/2012 03:41:04
olivier.larcheveque a quitté la salle 03:41
davin.baragiotta 31/08/2012 03:41:29
Django offre un lien automaitque... qui va nous permettre de faire en Python des requêtes sur la DB
sans faire de SQL 31/08/2012 03:41:34
c'est tout l'idée derrière l'ORM 31/08/2012 03:41:41
utilisons-le 31/08/2012 03:41:47
from annuaire.models import * 31/08/2012 03:41:59
on importe dans le shell tous les modèles codés dans annuaire.models(.py) 31/08/2012 03:42:18
l'ORM existe sur nos classes déclarées dans models.py 31/08/2012 03:42:41
car on les a fait héritées de models.Model.... c'est lui, l'ORM! 31/08/2012 03:42:55
le modèle suprême! 31/08/2012 03:43:08
ok 31/08/2012 03:43:09
pour accéder aux objets (rows) de notre classe Etablissement... on a ce qu'on techniquement on appelle un manager : 31/08/2012 03:43:41
object 31/08/2012 03:43:43
Etablissement.objects 31/08/2012 03:43:50
c'est lui qui manage l'accès à la DB, disons.... 31/08/2012 03:44:01
on a ensuite des méthodes sur objects... qui font en Python ce qu,on veut faire en SQL : 31/08/2012 03:44:28
.all() = sélectionne tous les rows sans condition 31/08/2012 03:44:41
pas de WHERE SQL 31/08/2012 03:44:46
essayez : 31/08/2012 03:44:53
etablissements = Etablissement.objects.all() 31/08/2012 03:45:06
(on stocke les rows dans variable etablissements) 31/08/2012 03:45:16
ça marche? 31/08/2012 03:45:25
on peut introspecter, comme dans l,atelier Python! 31/08/2012 03:45:36
type(etablissements) 31/08/2012 03:45:42
on voit que c'est un QuerySet 31/08/2012 03:45:52
darasy.nong a quitté la salle 03:46
davin.baragiotta 31/08/2012 03:46:08
sous-entendu... un ensemble d'objets provenant d'une requête
khone-cc 31/08/2012 03:46:15
Oui..
davin.baragiotta 31/08/2012 03:46:18
travaillons maintenant avec les données de la DB
etablissements... c'est un conteneur de vos rows... sous forme d'objet Python!!!! 31/08/2012 03:46:43
(oubliez les fetch results!!!) 31/08/2012 03:46:52
maintenat, on sait qu'on peut itérer sur les conteneurs (comme les listes) 31/08/2012 03:47:11
en faisant un for! 31/08/2012 03:47:15
allez-y! 31/08/2012 03:47:18
for e in etablissement: print e 31/08/2012 03:47:27
31/08/2012 03:47:28
au pluriel, désolé 31/08/2012 03:47:36
for e in etablissements : print e 31/08/2012 03:47:46
ahaha 31/08/2012 03:47:47
ça affiche une représentation (__unicode__) des Etablissements! 31/08/2012 03:48:05
comme dans l,admin, en fait! 31/08/2012 03:48:13
bon... on va prendre qu'un établissement 31/08/2012 03:48:21
en utilisant les index : 31/08/2012 03:48:26
e = etablissements[0] 31/08/2012 03:48:35
ça marche? 31/08/2012 03:48:38
khone-cc 31/08/2012 03:48:46
moi, ouip
davin.baragiotta 31/08/2012 03:48:49
des questions jusqu'à maintenant sur l'ORM?
on continue 31/08/2012 03:49:08
e = un seul objet... c'est plus un itérable 31/08/2012 03:49:18
khone-cc 31/08/2012 03:49:35
(10:50:09) Khone: e = etablissements[0] rien afficher?
davin.baragiotta 31/08/2012 03:49:38
on peut afficher son nom ou sigle... tous les champs déclarés dans models.py!
non, c,est une assignation 31/08/2012 03:49:47
khone-cc 31/08/2012 03:49:54
(c le suivant qui affiche)
davin.baragiotta 31/08/2012 03:50:09
on assigne dans la variable e l'indez 0 de etablissements
juste e 31/08/2012 03:50:17
ou print e 31/08/2012 03:50:19
affiche le unicode de ce seul objet 31/08/2012 03:50:25
e.nom 31/08/2012 03:50:28
e.sigle 31/08/2012 03:50:30
c'est magnifique, non? 31/08/2012 03:50:37
bien sûr, pareil avec les personnes!!!! 31/08/2012 03:50:49
je vais vous montrer comment appeler un seul résultat (pas plusieurs) 31/08/2012 03:51:14
.get() 31/08/2012 03:51:16
Personne.objects.get(id=1) 31/08/2012 03:51:29
p = Personne.objects.get(id=1) 31/08/2012 03:51:38
khone-cc 31/08/2012 03:51:43
Question tran.xuan.huy:
(10:49:54) tran.xuan.huy: je veux voir les sigle
(10:49:58) tran.xuan.huy: comment on va faire
davin.baragiotta 31/08/2012 03:51:45
(stockons le dans p, pour le manipuler
e.sigle 31/08/2012 03:51:51
possible que e n'ait pas de data pour sigle... c,est un champs facultatifs 31/08/2012 03:52:10
tu veux voir tous les sigles de la DB? 31/08/2012 03:52:16
for e in etablissements: print e.sigle 31/08/2012 03:52:23
(la ligne print pourrait être en-dessous + indentée... obligé si plusieurs lignes de traitement) 31/08/2012 03:52:54
ok pour sigle? 31/08/2012 03:52:58
khone-cc 31/08/2012 03:53:00
(10:53:09) tran.xuan.huy: non, c'est ok pour moi
davin.baragiotta 31/08/2012 03:53:03
p = qui?
print p 31/08/2012 03:53:11
Davin? 31/08/2012 03:53:15
si oui... je sais que dans les datas (je les ai saisies) il a une date de naissance : 31/08/2012 03:53:30
p.date_naissance 31/08/2012 03:53:34
je veux vous montrer 2 autres trucs de l'ORM 31/08/2012 03:53:58
filter() 31/08/2012 03:54:03
pour faire un WHERE 31/08/2012 03:54:09
personnes = Personne.objects.filter(nom='Baragiotta') 31/08/2012 03:54:30
sort toutes les personnes avec ce nom compliqué 31/08/2012 03:54:38
(pas juste un) 31/08/2012 03:54:50
on peut même généralisé la recherche 31/08/2012 03:55:05
avec des commandes qu'on trouve dans le lien de la doc fourni plus haut : 31/08/2012 03:55:16
personnes = Personne.objects.filter(nom__startswith='Bara') 31/08/2012 03:55:30
explicite... 31/08/2012 03:55:35
la magie est dans le double underscore : __startswith 31/08/2012 03:55:46
aussi, finalement... 31/08/2012 03:55:54
tran.xuan.huy a quitté la salle 03:56
Tri a quitté la salle 03:56
davin.baragiotta 31/08/2012 03:56:17
le filter peut se faire sur un champ associé par une ForeignKey
personnes = Personne.objects.filter(etablissement__nom__contains='Montréal') 31/08/2012 03:56:26
toutes les personnes qui ont ét.... 31/08/2012 03:56:36
ach 31/08/2012 03:56:37
dans le code c'est université 31/08/2012 03:56:42
: 31/08/2012 03:56:44
personnes = Personne.objects.filter(universite__nom__contains='Montréal') 31/08/2012 03:56:53
voilà 31/08/2012 03:56:56
toutes les personnes qui ont une université dont le nom contient "Montréal" 31/08/2012 03:57:16
31/08/2012 03:57:18
ça marche pour tous? 31/08/2012 03:57:27
khone-cc 31/08/2012 03:57:29
davin.baragiotta 31/08/2012 03:57:45
oubliez les reques complexes en SQL!
*requêtes 31/08/2012 03:57:52
tran.xuan.huy a rejoint le salon 03:57
Tri a rejoint le salon 03:58
davin.baragiotta 31/08/2012 03:58:16
ok, pendant que je fais une pause santé... voici un exercice :
le code que vous avez préféré, dans le shell... en explorant : 31/08/2012 03:58:31
copiez-le dans la fonction home() 31/08/2012 03:58:41
stockez l'infos que vous aimez dans les variables 31/08/2012 03:59:08
et passez les au template (à travers c = {} ) 31/08/2012 03:59:24
il faut au minimum la variable : 31/08/2012 03:59:40
etablissements = Etablissement.objects.all() 31/08/2012 03:59:45
svp 31/08/2012 03:59:47
(de retour dans 2 minutes) 31/08/2012 03:59:53
de retour 31/08/2012 04:02:07
davin.baragiotta a quitté la salle 04:08
davin.baragiotta a rejoint le salon 04:09
davin.baragiotta 31/08/2012 04:10:48
bon retombons sur nos pieds
on faisait quoi? 31/08/2012 04:10:52
on explorait, dans le shell... l'utilisation de l'ORM pour appeler la DB en Python (pas en SQL) 31/08/2012 04:11:14
pour créer des variables dans home() 31/08/2012 04:11:25
donc 31/08/2012 04:11:29
on va maintenant coder le fruit de nos investigations : 31/08/2012 04:11:42
ajoutez dans home : 31/08/2012 04:12:27
etablissements = Etablissement.objects.all()
c = {
'etablissements': etablissements,
} 31/08/2012 04:12:42
ensuite, dans le template 31/08/2012 04:12:54
au lieu de faire {{ etablissements }} 31/08/2012 04:13:04
je vais vous montrer à boucler avec le langage de templating de Django 31/08/2012 04:13:19
ouvrez home.html 31/08/2012 04:13:27
il existe des "tags" 31/08/2012 04:13:36
qu'on peut utiliser dasn les templates 31/08/2012 04:13:43
voici la doc : 31/08/2012 04:13:48
https://docs.djangoproject.com/en/1.1/ 31/08/2012 04:14:13
1.1 31/08/2012 04:14:16
dans le centre y,a "Templage layer" 31/08/2012 04:14:27
template, désolé 31/08/2012 04:14:34
built-in tags and filters : 31/08/2012 04:14:48
https://docs.djangoproject.com/en/1.1/ref/templates/builtins/#ref-templates-builtins 31/08/2012 04:14:48
filters = un peu comme filtres SPIP 31/08/2012 04:14:59
tag = plus puissant 31/08/2012 04:15:06
tag for 31/08/2012 04:15:12
https://docs.djangoproject.com/en/1.1/ref/templates/builtins/#for 31/08/2012 04:15:22
{% for e in etablissements %} 31/08/2012 04:15:35
ça ressemble beaucoup à Python 31/08/2012 04:15:44
mais c'en est pas 31/08/2012 04:15:48
faut finir tout tag 31/08/2012 04:15:58
avec son endtag 31/08/2012 04:16:02
{% endfor %} 31/08/2012 04:16:08
codez ceci dans votre template, pour le plaisir : 31/08/2012 04:16:20
khone-cc 31/08/2012 04:17:31
Classe Etablisement
{% for e in etablissements %}
{{ e }}
{% endfor %}
tran.xuan.huy a quitté la salle 04:17
davin.baragiotta 31/08/2012 04:17:39
ahaha oui!
Tri a quitté la salle 04:17
davin.baragiotta 31/08/2012 04:17:53
(je fatigue! )
Classe Etablisement
{% for e in etablissements %}
{{ e }}
{% endfor %} 31/08/2012 04:18:02
mieux 31/08/2012 04:18:07
ajoutez 31/08/2012 04:18:21
avant et après for 31/08/2012 04:18:25
pour faire du vrai HTML 31/08/2012 04:18:30
khone-cc 31/08/2012 04:18:35
ok
davin.baragiotta 31/08/2012 04:18:44
ok, vous voyez la liste des établissements?
maintenant... malheureusement l,atelier tire à sa fin 31/08/2012 04:19:21
on est déja`en retard 31/08/2012 04:19:28
mais moi j'ai un peu de temps 31/08/2012 04:19:33
khone-cc 31/08/2012 04:19:37
moi, ça à l'aire bien affiché ..
tran.xuan.huy a rejoint le salon 04:19
davin.baragiotta 31/08/2012 04:19:42
au mois pour conclure
Tri a rejoint le salon 04:19
davin.baragiotta 31/08/2012 04:19:59
revenons au plan :
ORM : utilisation réelle 31/08/2012 04:20:11
on est rendu dans l'utilisation réelle de l'ORM 31/08/2012 04:20:20
c'est fait 31/08/2012 04:20:22
rendez-vous compte des possibilités : 31/08/2012 04:20:31
vous appelez les données de la base de données comme vous voulez, pour créer une page HTML 31/08/2012 04:20:51
ça pourrait être du RSS 31/08/2012 04:20:58
appeller la DB pour lister dans un template respectant syntaxe RSS les nouvelles 31/08/2012 04:21:18
(mais y,a des outils qui font ça automatiquement) 31/08/2012 04:21:26
je voulais vous faire coder d'autres trucs 31/08/2012 04:21:40
mais tout est toujours trop long 31/08/2012 04:21:46
je vous propose donc de vous téléporter 31/08/2012 04:21:53
dans le temps 31/08/2012 04:21:55
en téléchargeant les sources finales de l'atelier 31/08/2012 04:22:03
avec plein truc dont je peux parler en démo 31/08/2012 04:22:13
(fini le code pour vous) 31/08/2012 04:22:18
ça vous va? 31/08/2012 04:22:21
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support?action=AttachFile&do=get&target=carto_1_1_final.tar.gz 31/08/2012 04:22:41
sources finales 31/08/2012 04:22:48
décompresser + aller dans répertoire 31/08/2012 04:23:05
+ python manage.py runserver 31/08/2012 04:23:12
tout le monde y est? 31/08/2012 04:24:19
Tri a quitté la salle 04:28
tran.xuan.huy a quitté la salle 04:28
Tri a rejoint le salon 04:30
Tri a quitté la salle 04:30
Tri a rejoint le salon 04:31
tran.xuan.huy a rejoint le salon 04:31
davin.baragiotta 31/08/2012 04:33:08
messieurs... l'heure est grave....
c'est la finale en feu d'artifice 31/08/2012 04:33:18
vous avez téléchargé les sources finales 31/08/2012 04:33:28
vous avez décompressé le .tar.gz 31/08/2012 04:33:40
vous êtes dans le répertoire du projet décompressé 31/08/2012 04:33:54
vous allumez le feu :
python manage.py runserver 31/08/2012 04:34:04
et allez sur : 31/08/2012 04:34:08
http://127.0.0.1:8000 31/08/2012 04:34:18
tadaaaaaaaaaaaaaaaaaaaaaaaaaam!!!!!! 31/08/2012 04:34:23
vous devriez avoir un super site avec des styles 31/08/2012 04:35:08
entre autres 31/08/2012 04:35:12
ça marche? (mais cachez votre joie!) 31/08/2012 04:35:23
tran.xuan.huy a quitté la salle 04:35
Tri a quitté la salle 04:35
davin.baragiotta 31/08/2012 04:36:55
bon je termine en vous montrant ce qui a été fait... que vous n'avez pas fait :
https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support 31/08/2012 04:37:04
héritage de template 31/08/2012 04:37:09
regardez bien... y,a un base.html 31/08/2012 04:37:17
qui déclare des {% block ... 31/08/2012 04:37:26
et toutes les autres pages 31/08/2012 04:37:33
{% extends "base.html" 31/08/2012 04:37:43
de sorte que tout le vrai code HTML qu'on veut pas coder dans chaque page 31/08/2012 04:37:57
est dans base.html 31/08/2012 04:38:01
et les autres pages remplissent les block 31/08/2012 04:38:10
autre chose 31/08/2012 04:38:14
les URLs avec paramètres 31/08/2012 04:38:24
ouvres annuaire/urls.py 31/08/2012 04:38:32
voyez la syntaxe particulière pour capter l'id 31/08/2012 04:38:43
ouvrez annuaire/views.py 31/08/2012 04:38:56
regardez le id passé à la fonction... qui nous permet de faire un .get() dans l'ORM... comme on a fait dans le shell 31/08/2012 04:39:25
avec ça : on fait une page de détail... pour CET établissement ou CETTE personne 31/08/2012 04:39:43
le plus impressionnant, c'est le style 31/08/2012 04:40:03
mais c'est rien d'autre que du CSS 31/08/2012 04:40:11
dans répertoire /media/ 31/08/2012 04:40:19
correctemetn configuré dans settings.py 31/08/2012 04:40:27
et utilisé dans base.html : {{ MEDIA_URL }} 31/08/2012 04:40:41
finalement... 31/08/2012 04:40:55
la connexion du user 31/08/2012 04:40:59
que je vous laisse expérimenter dans les interfaces 31/08/2012 04:41:11
et étudier sur : urls.py, connexion.html, deconnexion.html 31/08/2012 04:41:26
shafeek.sumser a quitté la salle 04:41
davin.baragiotta 31/08/2012 04:41:35
voilà, c'est tout?
(24 minutes de dépassé) 31/08/2012 04:41:53
des questions? 31/08/2012 04:41:55
nguyen.le.duc.huy 31/08/2012 04:42:46
ls
davin.baragiotta 31/08/2012 04:42:54
si pas de question... je conclue
ls = ? 31/08/2012 04:42:58
nguyen.le.duc.huy 31/08/2012 04:42:58
Pardon trompe la fenentre
davin.baragiotta 31/08/2012 04:43:02
ah!
khone-cc 31/08/2012 04:43:32
(11:43:37) khuon.tiv: Combien de web codes ont dans cet interface ? Python-Django CSS HTML quoi d'autre ?
davin.baragiotta 31/08/2012 04:44:38
web codes? pas sûr de comprendre... mais les technos impliqués :
oui : python, django (framework Python), Apache éventuellement, HTTP, CSS, HTML, JS au besoin 31/08/2012 04:45:04
voir le schéma : 31/08/2012 04:45:07
http://montrealpython.org/r/attachments/13/web-development.jpg 31/08/2012 04:45:15
shafeek.sumser a rejoint le salon 04:45
davin.baragiotta 31/08/2012 04:45:25
autres questions?
khone-cc 31/08/2012 04:45:40
Non
yeap, GRAND MERCI PROF PYTHON-DJANGO... 31/08/2012 04:45:43
davin.baragiotta 31/08/2012 04:45:59
khone-cc 31/08/2012 04:46:01
on lui laisse à Dodo...
davin.baragiotta 31/08/2012 04:46:05
je conclue donc rapido :
vous avex une bombe entre les mains : 31/08/2012 04:46:13
la puissance de Python sur le web 31/08/2012 04:46:19
tout ce que vous êtes capables de faire avec des import de Python... 31/08/2012 04:46:37
... vous pouvez l'utiliser sur le web avec les views... 31/08/2012 04:46:49
et stocker vos data dans une DB 31/08/2012 04:46:57
(là c'était sqlite... mais on peut mettre MySQL évidemment, ou autre) 31/08/2012 04:47:20
tous nos projets SI de l'AUF = Django 31/08/2012 04:47:32
y,a du Python partant dans git.auf.org! 31/08/2012 04:47:41
je vous laisse apprécier la montée en puissance que vous venez de faire 31/08/2012 04:47:57
et surtout 31/08/2012 04:47:58
on est tous ensemble, tout le temps... la communauté tech : 31/08/2012 04:48:10
on vit dans le salon tech, ari-si ou autres 31/08/2012 04:48:18
shafeek.sumser 31/08/2012 04:48:29
davin une dernière question: est-ce qu'avec django on peut faire du ajax et jquery?
davin.baragiotta 31/08/2012 04:48:30
n'hésitez à poser les questions et...
... on n'est pas obligés d,attendre la prochaine semaine Tech pour continuer d'apprendre et collaborer 31/08/2012 04:48:55
réponse : 31/08/2012 04:48:59
oui, Ajax = rien d'autre qu'un appel de JS sur serveur... 31/08/2012 04:49:15
un appel partiel, en quelque sorte car veut pas une page complète 31/08/2012 04:49:36
donc 31/08/2012 04:49:37
on met le code JQuery qu'on veut dans notre template HTML 31/08/2012 04:49:52
dans une balise link qui lie vers un script : dans /media/js ( {{ MEDIA_URL }}/js/le_script_qui_tue.js 31/08/2012 04:50:35
ensuite 31/08/2012 04:50:41
ce script appelle une URL 31/08/2012 04:50:47
gérée dans urls.py 31/08/2012 04:50:51
qui appelle une fonction dans views.py 31/08/2012 04:51:01
qui retourne un FRAGMENT HTML 31/08/2012 04:51:10
même principe qu'on vient de voir 31/08/2012 04:51:18
sauf un appel partiel pour raffraichir un fragmenr de code 31/08/2012 04:51:30
le JS dans jQuery qui reçoit la réponse partielle... 31/08/2012 04:51:47
... va ajouter ce fragment dans le DOM en cours 31/08/2012 04:51:57
shafeek.sumser 31/08/2012 04:52:00
ok j'étais pas présent, viens d'arriver au bureau je rattraperai ce soir
davin.baragiotta 31/08/2012 04:52:03
voilà
ok à ce soir (ce matin pour moi... en fait ) 31/08/2012 04:52:18
}}}
---------------------- FIN ATELIER DJANGO FRONTEND -------------------------------- 31/08/2012 04:52:35