Atelier Django Frontend : interfaces publiques d'un site
Sommaire
Transcriptions des ateliers dispensés par messagerie instantanée dans le cadre de la Semaine tech 2012
Transcription séance du 2012-08-31 02h00 GMT
22h00 heure locale retranscrite ici
[...] historique tronqué suite à rupture connexion... [...] reprise autour de la partie ORM (23:56:46) davin.baragiotta: dans le code c'est université (23:56:47) davin.baragiotta: : (23:56:56) davin.baragiotta: personnes = Personne.objects.filter(universite__nom__contains='Montréal') (23:57:00) davin.baragiotta: voilà (23:57:20) davin.baragiotta: toutes les personnes qui ont une université dont le nom contient "Montréal" (23:57:21) davin.baragiotta: :D (23:57:31) davin.baragiotta: ça marche pour tous? (23:57:33) khone-cc: :-o (23:57:49) davin.baragiotta: oubliez les reques complexes en SQL! (23:57:56) davin.baragiotta: *requêtes (23:58:20) davin.baragiotta: ok, pendant que je fais une pause santé... voici un exercice : (23:58:35) davin.baragiotta: le code que vous avez préféré, dans le shell... en explorant : (23:58:45) davin.baragiotta: copiez-le dans la fonction home() (23:59:12) davin.baragiotta: stockez l'infos que vous aimez dans les variables (23:59:27) davin.baragiotta: et passez les au template (à travers c = {} ) (23:59:43) davin.baragiotta: il faut au minimum la variable : (23:59:49) davin.baragiotta: etablissements = Etablissement.objects.all() (23:59:50) davin.baragiotta: svp ;) (23:59:57) davin.baragiotta: (de retour dans 2 minutes) (00:02:10) davin.baragiotta: de retour (00:10:52) davin.baragiotta: bon retombons sur nos pieds (00:10:55) davin.baragiotta: on faisait quoi? (00:11:18) davin.baragiotta: on explorait, dans le shell... l'utilisation de l'ORM pour appeler la DB en Python (pas en SQL) (00:11:29) davin.baragiotta: pour créer des variables dans home() (00:11:32) davin.baragiotta: donc (00:11:45) davin.baragiotta: on va maintenant coder le fruit de nos investigations : (00:12:31) davin.baragiotta: ajoutez dans home : (00:12:46) davin.baragiotta: etablissements = Etablissement.objects.all() c = { 'etablissements': etablissements, } (00:12:57) davin.baragiotta: ensuite, dans le template (00:13:08) davin.baragiotta: au lieu de faire {{ etablissements }} (00:13:23) davin.baragiotta: je vais vous montrer à boucler avec le langage de templating de Django (00:13:31) davin.baragiotta: ouvrez home.html (00:13:39) davin.baragiotta: il existe des "tags" (00:13:47) davin.baragiotta: qu'on peut utiliser dasn les templates (00:13:52) davin.baragiotta: voici la doc : (00:14:16) davin.baragiotta: https://docs.djangoproject.com/en/1.1/ (00:14:20) davin.baragiotta: 1.1 (00:14:31) davin.baragiotta: dans le centre y,a "Templage layer" (00:14:38) davin.baragiotta: template, désolé (00:14:51) davin.baragiotta: built-in tags and filters : (00:14:52) davin.baragiotta: https://docs.djangoproject.com/en/1.1/ref/templates/builtins/#ref-templates-builtins (00:15:02) davin.baragiotta: filters = un peu comme filtres SPIP (00:15:10) davin.baragiotta: tag = plus puissant ;) (00:15:15) davin.baragiotta: tag for (00:15:25) davin.baragiotta: https://docs.djangoproject.com/en/1.1/ref/templates/builtins/#for (00:15:38) davin.baragiotta: {% for e in etablissements %} (00:15:48) davin.baragiotta: ça ressemble beaucoup à Python (00:15:52) davin.baragiotta: mais c'en est pas (00:16:01) davin.baragiotta: faut finir tout tag (00:16:06) davin.baragiotta: avec son endtag (00:16:12) davin.baragiotta: {% endfor %} (00:16:24) davin.baragiotta: codez ceci dans votre template, pour le plaisir : (00:17:35) khone-cc: <h2>Classe Etablisement</h2> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} (00:17:43) davin.baragiotta: ahaha oui! (00:17:57) davin.baragiotta: (je fatigue! ;) ) (00:18:06) davin.baragiotta: <h2>Classe Etablisement</h2> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} (00:18:11) davin.baragiotta: mieux (00:18:25) davin.baragiotta: ajoutez <ul> et </ul> (00:18:29) davin.baragiotta: avant et après for (00:18:34) davin.baragiotta: pour faire du vrai HTML ;) (00:18:39) khone-cc: ok (00:18:48) davin.baragiotta: ok, vous voyez la liste des établissements? (00:19:25) davin.baragiotta: maintenant... malheureusement l,atelier tire à sa fin (00:19:31) davin.baragiotta: on est déja`en retard (00:19:37) davin.baragiotta: mais moi j'ai un peu de temps (00:19:40) khone-cc: moi, ça à l'aire bien affiché .. (00:19:46) davin.baragiotta: au mois pour conclure ;) (00:20:03) davin.baragiotta: revenons au plan : (00:20:15) davin.baragiotta: ORM : utilisation réelle (00:20:23) davin.baragiotta: on est rendu dans l'utilisation réelle de l'ORM (00:20:26) davin.baragiotta: c'est fait (00:20:35) davin.baragiotta: rendez-vous compte des possibilités : (00:20:55) davin.baragiotta: vous appelez les données de la base de données comme vous voulez, pour créer une page HTML (00:21:02) davin.baragiotta: ça pourrait être du RSS (00:21:21) davin.baragiotta: appeller la DB pour lister dans un template respectant syntaxe RSS les nouvelles (00:21:30) davin.baragiotta: (mais y,a des outils qui font ça automatiquement) (00:21:44) davin.baragiotta: je voulais vous faire coder d'autres trucs (00:21:50) davin.baragiotta: mais tout est toujours trop long (00:21:57) davin.baragiotta: je vous propose donc de vous téléporter (00:21:59) davin.baragiotta: dans le temps (00:22:07) davin.baragiotta: en téléchargeant les sources finales de l'atelier (00:22:16) davin.baragiotta: avec plein truc dont je peux parler en démo (00:22:22) davin.baragiotta: (fini le code pour vous) (00:22:25) davin.baragiotta: ça vous va? (00:22:45) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support?action=AttachFile&do=get&target=carto_1_1_final.tar.gz (00:22:52) davin.baragiotta: sources finales (00:23:08) davin.baragiotta: décompresser + aller dans répertoire (00:23:16) davin.baragiotta: + python manage.py runserver (00:24:23) davin.baragiotta: tout le monde y est? (00:33:11) davin.baragiotta: messieurs... l'heure est grave.... (00:33:21) davin.baragiotta: c'est la finale en feu d'artifice (00:33:31) davin.baragiotta: vous avez téléchargé les sources finales (00:33:43) davin.baragiotta: vous avez décompressé le .tar.gz (00:33:58) davin.baragiotta: vous êtes dans le répertoire du projet décompressé (00:34:08) davin.baragiotta: vous allumez le feu : python manage.py runserver (00:34:12) davin.baragiotta: et allez sur : (00:34:22) davin.baragiotta: http://127.0.0.1:8000 (00:34:27) davin.baragiotta: tadaaaaaaaaaaaaaaaaaaaaaaaaaam!!!!!! (00:35:12) davin.baragiotta: vous devriez avoir un super site avec des styles (00:35:15) davin.baragiotta: entre autres (00:35:26) davin.baragiotta: ça marche? (mais cachez votre joie!) (00:36:59) davin.baragiotta: bon je termine en vous montrant ce qui a été fait... que vous n'avez pas fait : (00:37:07) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (00:37:13) davin.baragiotta: héritage de template (00:37:20) davin.baragiotta: regardez bien... y,a un base.html (00:37:30) davin.baragiotta: qui déclare des {% block ... (00:37:37) davin.baragiotta: et toutes les autres pages (00:37:47) davin.baragiotta: {% extends "base.html" (00:38:01) davin.baragiotta: de sorte que tout le vrai code HTML qu'on veut pas coder dans chaque page (00:38:05) davin.baragiotta: est dans base.html (00:38:14) davin.baragiotta: et les autres pages remplissent les block (00:38:18) davin.baragiotta: autre chose (00:38:27) davin.baragiotta: les URLs avec paramètres (00:38:36) davin.baragiotta: ouvres annuaire/urls.py (00:38:47) davin.baragiotta: voyez la syntaxe particulière pour capter l'id (00:39:00) davin.baragiotta: ouvrez annuaire/views.py (00:39:28) davin.baragiotta: regardez le id passé à la fonction... qui nous permet de faire un .get() dans l'ORM... comme on a fait dans le shell (00:39:47) davin.baragiotta: avec ça : on fait une page de détail... pour CET établissement ou CETTE personne (00:40:06) davin.baragiotta: le plus impressionnant, c'est le style (00:40:15) davin.baragiotta: mais c'est rien d'autre que du CSS (00:40:23) davin.baragiotta: dans répertoire /media/ (00:40:31) davin.baragiotta: correctemetn configuré dans settings.py (00:40:45) davin.baragiotta: et utilisé dans base.html : {{ MEDIA_URL }} (00:40:59) davin.baragiotta: finalement... (00:41:03) davin.baragiotta: la connexion du user (00:41:15) davin.baragiotta: que je vous laisse expérimenter dans les interfaces (00:41:30) davin.baragiotta: et étudier sur : urls.py, connexion.html, deconnexion.html (00:41:38) davin.baragiotta: voilà, c'est tout? (00:41:56) davin.baragiotta: (24 minutes de dépassé) (00:41:59) davin.baragiotta: des questions? (00:42:58) davin.baragiotta: si pas de question... je conclue (00:43:36) khone-cc: (11:43:37) khuon.tiv: Combien de web codes ont dans cet interface ? Python-Django CSS HTML quoi d'autre ? (00:44:41) davin.baragiotta: web codes? pas sûr de comprendre... mais les technos impliqués : (00:45:08) davin.baragiotta: oui : python, django (framework Python), Apache éventuellement, HTTP, CSS, HTML, JS au besoin (00:45:11) davin.baragiotta: voir le schéma : (00:45:19) davin.baragiotta: http://montrealpython.org/r/attachments/13/web-development.jpg (00:45:28) davin.baragiotta: autres questions? (00:45:43) khone-cc: Non (00:45:46) khone-cc: yeap, GRAND MERCI PROF PYTHON-DJANGO... (00:46:02) davin.baragiotta: :D (00:46:04) khone-cc: on lui laisse à Dodo... (00:46:09) davin.baragiotta: je conclue donc rapido : (00:46:16) davin.baragiotta: vous avex une bombe entre les mains : (00:46:23) davin.baragiotta: la puissance de Python sur le web (00:46:40) davin.baragiotta: tout ce que vous êtes capables de faire avec des import de Python... (00:46:52) davin.baragiotta: ... vous pouvez l'utiliser sur le web avec les views... (00:47:00) davin.baragiotta: et stocker vos data dans une DB (00:47:24) davin.baragiotta: (là c'était sqlite... mais on peut mettre MySQL évidemment, ou autre) (00:47:36) davin.baragiotta: tous nos projets SI de l'AUF = Django (00:47:45) davin.baragiotta: y,a du Python partant dans git.auf.org! (00:48:00) davin.baragiotta: je vous laisse apprécier la montée en puissance que vous venez de faire (00:48:02) davin.baragiotta: et surtout (00:48:13) davin.baragiotta: on est tous ensemble, tout le temps... la communauté tech : (00:48:22) davin.baragiotta: on vit dans le salon tech, ari-si ou autres (00:48:32) shafeek.sumser: davin une dernière question: est-ce qu'avec django on peut faire du ajax et jquery? (00:48:33) davin.baragiotta: n'hésitez à poser les questions et... (00:48:59) davin.baragiotta: ... on n'est pas obligés d,attendre la prochaine semaine Tech pour continuer d'apprendre et collaborer ;) (00:49:02) davin.baragiotta: réponse : (00:49:19) davin.baragiotta: oui, Ajax = rien d'autre qu'un appel de JS sur serveur... (00:49:39) davin.baragiotta: un appel partiel, en quelque sorte car veut pas une page complète (00:49:40) davin.baragiotta: donc (00:49:55) davin.baragiotta: on met le code JQuery qu'on veut dans notre template HTML (00:50:39) davin.baragiotta: dans une balise link qui lie vers un script : dans /media/js ( {{ MEDIA_URL }}/js/le_script_qui_tue.js (00:50:45) davin.baragiotta: ensuite (00:50:50) davin.baragiotta: ce script appelle une URL (00:50:55) davin.baragiotta: gérée dans urls.py (00:51:05) davin.baragiotta: qui appelle une fonction dans views.py (00:51:14) davin.baragiotta: qui retourne un FRAGMENT HTML (00:51:22) davin.baragiotta: même principe qu'on vient de voir (00:51:34) davin.baragiotta: sauf un appel partiel pour raffraichir un fragmenr de code (00:51:51) davin.baragiotta: le JS dans jQuery qui reçoit la réponse partielle... (00:52:00) davin.baragiotta: ... va ajouter ce fragment dans le DOM en cours (00:52:03) shafeek.sumser: ok j'étais pas présent, viens d'arriver au bureau je rattraperai ce soir (00:52:06) davin.baragiotta: voilà ;) (00:52:22) davin.baragiotta: ok à ce soir (ce matin pour moi... en fait ;) ) (00:52:39) davin.baragiotta: ---------------------- FIN ATELIER DJANGO FRONTEND --------------------------------
Transcription séance du 2012-08-31 15h00 GMT
11h00 heure locale retranscrite ici
(11:30:40) davin.baragiotta: --------- ATELIER DJANGO : Frontend : interfaces publiques --------------- (11:30:50) davin.baragiotta: Le plan de l,atelier est ici : (11:31:01) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (11:31:06) davin.baragiotta: INTRODUCTION (11:31:27) davin.baragiotta: si des personnes n'ont pas suivi l'atelier Backend (pas obligatoire) (11:31:39) davin.baragiotta: le dire dans tehc à modératuer niry.andriambelo svp (11:31:40) davin.baragiotta: tech (11:31:42) davin.baragiotta: ok (11:31:46) davin.baragiotta: notre objectif maintenant (11:32:04) davin.baragiotta: c'est de créer des interfaces web (HTML) d'affichage de nos données (11:32:10) davin.baragiotta: non, ce n'est pas un atelier HTML (11:32:36) davin.baragiotta: je suppose que tout le monde a Django 1.1.1 (11:32:43) davin.baragiotta: RAPPELS (11:33:00) davin.baragiotta: reprenons le schéma sur le développement web (11:33:07) davin.baragiotta: http://montrealpython.org/r/attachments/13/web-development.jpg (11:33:26) davin.baragiotta: on a vu urls.py (un peu...) (11:33:29) davin.baragiotta: models.py (11:33:31) davin.baragiotta: et admin.py (11:33:46) davin.baragiotta: maintenant, on va travailler dans urls.py, views.py et template (11:34:10) davin.baragiotta: en gros... l,admin fournit des interfaces toutes faites pour gestion habituelle.... (11:34:21) davin.baragiotta: là on va faire les interfaces à la main... créer notre site quoi! (11:34:38) davin.baragiotta: pour pouvoir afficher nos données (11:34:47) davin.baragiotta: en fait, pour simplifier l'atelier (11:34:59) davin.baragiotta: je propose que nous partions tous du même code (11:35:02) davin.baragiotta: avec les mêmes données (11:35:05) davin.baragiotta: ce sera plus simple (11:35:15) davin.baragiotta: téléchargez l'archive : (11:35:20) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support%3Faction%3DAttachFile%26do%3Dget%26target%3Dcarto_1_1_backend_final.tar.gz (11:35:27) davin.baragiotta: décompressez (11:35:36) davin.baragiotta: grrrr (11:35:48) davin.baragiotta: je hais les pièces jointes de moinmoin (11:35:59) davin.baragiotta: minute (11:36:19) davin.baragiotta: http://git.auf.org/?p=davin.git;a=commit;h=c0c1a067233e527f80c08b4f9d2fd84db5ca5269 (11:36:29) davin.baragiotta: mes sources sur mon dépôt git perso... (11:36:31) davin.baragiotta: davin.git (11:36:47) davin.baragiotta: sur ce lien, cliquer sur "snapshot" (11:36:53) davin.baragiotta: http://git.auf.org/?p=davin.git;a=snapshot;h=c0c1a067233e527f80c08b4f9d2fd84db5ca5269;sf=tgz (11:37:09) davin.baragiotta: vous avez TOUT mon dépôt personnel... (11:37:13) davin.baragiotta: ce qui nous intéresse (11:37:20) davin.baragiotta: (après décompression) (11:37:23) davin.baragiotta: c'est ici : (11:37:52) davin.baragiotta: davin-c0c1a06/ateliers/django/carto_1_1 (11:38:04) davin.baragiotta: copier ce répertoire à côté de votre carto, si vous voulez (11:38:23) davin.baragiotta: voilà... (11:38:50) davin.baragiotta: on va voir ce que ce projet... qui correspond au code complet de l,atelier Backend (même les trucs pas couverts) (11:38:54) davin.baragiotta: avec un bon jeu de données (11:38:59) davin.baragiotta: cd carto_1_1 (11:39:06) davin.baragiotta: python manage.py runserver (11:39:56) davin.baragiotta: vous devriez pouvoir accéder à l'admin : (11:40:09) davin.baragiotta: admin/admin (11:40:21) davin.baragiotta: regardez les données (11:40:30) davin.baragiotta: y,a 11 établissemetns (11:40:38) davin.baragiotta: 24 personnes (11:40:42) davin.baragiotta: ok pour tous? (11:40:44) davin.baragiotta: des questions? (11:40:56) niry.andriambelo: non (11:41:21) niry.andriambelo: on suppose que oui, personne ne dit le contraire (11:41:22) davin.baragiotta: ok super... on a donc tous les mêmes données à afficher dans nos pages (11:41:30) davin.baragiotta: qui ne dit mot, consent ;) (11:41:47) davin.baragiotta: je crois que la première étape... c'est de se créer une page d'accueil :D (11:41:58) davin.baragiotta: tapez : (11:42:06) davin.baragiotta: http://127.0.0.1:8000/ (11:42:12) davin.baragiotta: 404... (11:42:14) davin.baragiotta: c'est nul (11:42:20) davin.baragiotta: on n'a pas de page d'accueil (11:42:35) davin.baragiotta: première étape = ? point d'entrée = ? (11:42:38) davin.baragiotta: urls.py (11:43:03) davin.baragiotta: from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', # Example: # (r'^carto/', include('carto.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: (r'^admin/', include(admin.site.urls)), ) (11:43:19) davin.baragiotta: bon on se rappelle que urls.py = les règles... patterns d'URL gérées (11:43:25) davin.baragiotta: on n'a que admin/ (11:43:28) davin.baragiotta: on va créer / (11:43:51) davin.baragiotta: je vous donne le code (11:43:53) davin.baragiotta: et on en parle (11:44:12) davin.baragiotta: url(r'^$', 'carto_1_1.views.home', name='home'), (11:44:23) davin.baragiotta: from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^$', 'carto_1_1.views.home', name='home'), # Example: # (r'^carto/', include('carto.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: (r'^admin/', include(admin.site.urls)), ) (11:44:36) davin.baragiotta: lisons (11:44:57) davin.baragiotta: (attention... le projet s'appelle carto_1_1... pas carto... oui je sais c'est laid) (11:45:15) davin.baragiotta: j'ai ajouté une nouvelle règle (11:45:22) davin.baragiotta: avec fonction url() (11:45:37) davin.baragiotta: qui elle, on le voit pas, mais est importée avec le * de from django.conf.urls.defaults import * (11:45:47) davin.baragiotta: url() prend 3 params : (11:46:21) davin.baragiotta: 1. le pattern qui doit matcher (un pattern de regex, regular expression... voir module re de standard library) (11:46:46) davin.baragiotta: 2. la vue qui doit être exécutée pour créer la réponse à la requête (11:46:58) davin.baragiotta: 3. un nom, par commodité, pour faire référence à cette règle (11:47:00) davin.baragiotta: donc (11:47:03) davin.baragiotta: lisons : (11:47:08) davin.baragiotta: url(r'^$', 'carto_1_1.views.home', name='home'), (11:47:42) davin.baragiotta: l'URL qui commence (^) avec et qui finit avec ($) rien... (11:48:15) davin.baragiotta: ... sera traitée par la fonction home() dans le fichier views.py du projet carto_1_1... (11:48:30) davin.baragiotta: (par ailleurs cette règle s'appelle "home") (11:48:41) davin.baragiotta: commence et finit avec rien... (11:48:54) davin.baragiotta: entre ^ et $... ben il n'y a pas de caractère dans le pattern (11:49:16) davin.baragiotta: donc strictement... ça veut dire : si j'appelle mon URL juset avec le nom de domaine... sans rien derrière, ça amtche (11:49:26) davin.baragiotta: c'est donc notre root, notre page d'accueuil (11:49:30) davin.baragiotta: super, on teste!!!!! (11:49:47) davin.baragiotta: from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^$', 'carto_1_1.views.home', name='home'), # Example: # (r'^carto/', include('carto.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: (r'^admin/', include(admin.site.urls)), ) (11:49:52) davin.baragiotta: + sauvegarde ;) (11:49:59) davin.baragiotta: http://127.0.0.1:8000/ (11:50:39) davin.baragiotta: hmmm... je m'attendais à une erreur... pas au 404 :( (11:50:56) davin.baragiotta: ahaha, je suis pas dans le bon projet! ;) (11:51:15) davin.baragiotta: (j'étais encore dans carto... faut être dans carto_1_1) (11:51:36) davin.baragiotta: hourra! erreur! (11:51:41) davin.baragiotta: ViewDoesNotExist at / (11:51:48) davin.baragiotta: Could not import carto_1_1.views. Error was: No module named views (11:52:12) davin.baragiotta: ouaip... en effet... le fichier views.py n'existe pas (11:52:18) davin.baragiotta: on va le créer à la racine du projet (11:52:34) davin.baragiotta: ah... vous pourriez dire "oui mais il existe dans annuaire/views.py" (11:53:00) davin.baragiotta: la page d'accueil... est indépendante des apps... c'est un choix de design que j'impose ;) (11:53:22) davin.baragiotta: donc je veux pas que ce soit dans un app particulièrement, mais à la racine du projet, pour la page d'accueil (11:53:33) davin.baragiotta: alors créons : carto_1_1/views.py (11:53:57) davin.baragiotta: je vous donne le code de base et on discute (11:54:07) davin.baragiotta: on veut créer la focntion home() (11:54:46) davin.baragiotta: le code est dans la page de l,atelier : (11:54:51) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (11:55:04) davin.baragiotta: django 1.1.1 (11:55:05) davin.baragiotta: 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)) (11:55:08) davin.baragiotta: grrr... (11:55:15) davin.baragiotta: 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)) (11:55:23) davin.baragiotta: ok lisons (11:55:31) davin.baragiotta: premières lignes... des imports... (11:55:40) davin.baragiotta: faut juste vérifier que ce qui est importé est utilisé (11:55:58) davin.baragiotta: render_to_response, Context, RequestContext... ok tout est utilisé plus bas (11:56:08) davin.baragiotta: def home(): (11:56:16) davin.baragiotta: def = pour créer fonction en Python (11:56:25) davin.baragiotta: home = nom de la fonction (11:56:39) davin.baragiotta: entre les parenthèses... les paramètres (11:56:56) davin.baragiotta: request : aaaaaah.... input = requête et output = réponse? (11:57:02) davin.baragiotta: oui (11:57:16) davin.baragiotta: l'output d'une fonction... c'est ce qu'elle retourne : (11:57:23) davin.baragiotta: return render_to_response() (11:57:41) davin.baragiotta: on utilise une fonction pour "rendre en réponse" (11:57:53) davin.baragiotta: ce qu'on va "rendre"... c'est un template HTML (11:57:59) davin.baragiotta: ici, c'est home.html (11:58:29) davin.baragiotta: les autres params de render_to_responses... sont du contexte que l'on passe au template... (11:58:43) davin.baragiotta: ... pour qu'il ait des variables (on y reviwent) (11:58:48) davin.baragiotta: ok testons (11:58:49) davin.baragiotta: :D (11:58:59) davin.baragiotta: refresh : http://127.0.0.1:8000/ (11:59:09) davin.baragiotta: hourra! une autre erreur! (11:59:10) davin.baragiotta: ;) (11:59:21) davin.baragiotta: (ça veut dire qu'on a réglé la première ;) ) (11:59:26) davin.baragiotta: TemplateDoesNotExist at / (11:59:30) davin.baragiotta: home.html (11:59:33) davin.baragiotta: mouaip... (11:59:50) davin.baragiotta: c'est vrai qu'on n,a pas créé encore le template home.html demandé par / (11:59:55) davin.baragiotta: on le fait? on est rendu là ;) (12:00:11) davin.baragiotta: ok, encore un peu de config dans notre jeune projet (12:00:24) davin.baragiotta: créons un répertoire "templates" à la racine du projet (12:00:41) davin.baragiotta: templates... c'est le nom par convention (12:00:55) davin.baragiotta: on va créer dedans, le fichier home.html (12:01:26) davin.baragiotta: dans home.html... on mettre du contenu bien... genre : <h1>Bonjour AUF</h1> (12:01:56) davin.baragiotta: pour ceux moins à l,aise avec HTML... pas de probl.. rien de compliqué ici (12:02:03) davin.baragiotta: refresh? (12:02:10) davin.baragiotta: TemplateDoesNotExist at / (12:02:11) davin.baragiotta: pareil (12:02:24) davin.baragiotta: en fait, faut configurer dans settings.py où se trouvent les templates (12:02:34) davin.baragiotta: settings.py TEMPLATE_DIRS (12:02:47) davin.baragiotta: TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) (12:02:50) davin.baragiotta: lisons.,.. (12:03:08) davin.baragiotta: absolute paths... mouais.... (12:03:17) davin.baragiotta: mais quand je vais déployer mon code sur serveur (12:03:37) davin.baragiotta: j'ai pas envie de venir modifier ce settings... (on pourrait mais c'est nul) (12:04:02) davin.baragiotta: on va donc créer dynamiquement, en Python, le chemin absolu.... et on va le faire à partir de l'emplacement de settings.py (12:04:11) davin.baragiotta: en haut, dans settings.py (12:04:14) davin.baragiotta: import os (12:04:29) davin.baragiotta: os : c'est un module de la standard library (12:04:39) davin.baragiotta: sert à manipuler syst de fichiers, notamment (12:04:42) davin.baragiotta: puissant ;) (12:04:49) davin.baragiotta: ensuite, ajouter : (12:05:02) davin.baragiotta: modifier TEMPLATE_DIRS (12:05:25) davin.baragiotta: TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), "templates"), ) (12:05:28) davin.baragiotta: TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), "templates"), ) (12:05:34) davin.baragiotta: voila... lisons.... (12:06:10) davin.baragiotta: __file__ = variable représentation le fichier en cours d'exécution... settings.py dans le contexte... (12:06:31) davin.baragiotta: .dirname() va chercher tout le path absolu de settings.py (12:07:02) davin.baragiotta: .join() joint le path absolu de settings path au string final "templates" (12:07:35) davin.baragiotta: donc répertoire templates, se trouve absolument à côté de settings.py (12:07:38) davin.baragiotta: vouala (12:07:41) davin.baragiotta: refresh???? (12:08:16) davin.baragiotta: Bonjour AUF (12:08:18) davin.baragiotta: :D (12:08:24) davin.baragiotta: ça marche pour tous? (12:08:29) davin.baragiotta: questions? (12:08:51) niry.andriambelo: darko.stanar: NameError: name 'os' is not defined (12:09:20) davin.baragiotta: faut pas oublier d'importer ce qu'on utilise : (12:09:25) davin.baragiotta: en haute de fichier : import os (12:09:39) davin.baragiotta: permet de faire : os.path.... (12:09:45) davin.baragiotta: ok? (12:10:04) niry.andriambelo: pas d'autres remarques donc ok (12:10:08) davin.baragiotta: super... (12:10:13) davin.baragiotta: on a fait quoi? (12:10:19) davin.baragiotta: modifié urls.py (12:10:34) davin.baragiotta: créé home() pour / dans views.py (12:10:43) davin.baragiotta: et créé le templates (+ config) (12:10:58) davin.baragiotta: on vient de faire le chainage complet du frontend (12:11:05) davin.baragiotta: mais (12:11:07) davin.baragiotta: c'est nul (12:11:17) davin.baragiotta: car bonjour AUF... c'est une page statique (12:11:24) davin.baragiotta: on veut afficher une variable (12:11:34) davin.baragiotta: on va donc créer une variable dans home() (12:11:39) davin.baragiotta: et la passer au template ;) (12:11:43) davin.baragiotta: views.py : (12:11:56) davin.baragiotta: codons une variable bidon : (12:12:02) davin.baragiotta: variable = "Davin" (12:12:22) davin.baragiotta: attention à indentation (12:12:35) davin.baragiotta: doit être aligné avec c = {}.... sous def (12:12:43) davin.baragiotta: pour la passer au template.... (12:12:57) davin.baragiotta: on va stocker toutes les variables dans le dictionnaire c (12:13:11) davin.baragiotta: on voit que c = dictionnaire car utilise {} (12:13:30) davin.baragiotta: rappel : un dictionnaire est un ensemble de clé-valeur (12:13:39) davin.baragiotta: on va donc créer une clé : 'var' (12:13:49) davin.baragiotta: il donner la valeur de notre variable : (12:14:16) davin.baragiotta: from django.shortcuts import render_to_response from django.template import Context, RequestContext def home(request): variable = "Davin" c = { 'var':variable, } return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) (12:14:36) davin.baragiotta: 'var' sera le nom de la variable dans le template... (12:14:49) davin.baragiotta: essayons maintenant d'afficher cette variable dans le template (12:14:57) davin.baragiotta: templates/home.html : (12:15:10) davin.baragiotta: ajoutez {{ var }} (12:15:28) davin.baragiotta: <h1>Bonjour AUF</h1> {{ var }} (12:15:49) davin.baragiotta: attention : on n,est plus dans du Python.... on est dans le langage de template de Django (12:16:12) davin.baragiotta: il existe, dans l'univers Python, d'autres moteur de template... avec leur propre syntaxe (ex.: mako) (12:16:26) davin.baragiotta: mais Django est monolithique : il utilise son propre moteur... (12:16:38) davin.baragiotta: la doc des conventions syntaxiques esst donc dans la doc de Django : (12:16:46) davin.baragiotta: https://docs.djangoproject.com/en/1.1// (12:16:52) davin.baragiotta: sous Template layer : (12:17:21) davin.baragiotta: Syntax overview et Built-in tags and filters = l'important pour nous (12:17:23) davin.baragiotta: on y revient (12:17:24) davin.baragiotta: donc (12:17:27) davin.baragiotta: {{ }} (12:17:38) davin.baragiotta: c'est la syntaxe pour afficher une variable (12:17:41) davin.baragiotta: ok, refresh (12:18:09) davin.baragiotta: si vous voyez rien, relisez et corrigez code... et n'oubliez pas de sauvegarder (12:18:11) davin.baragiotta: ;) (12:18:19) davin.baragiotta: cool... je vois ceci : (12:18:24) davin.baragiotta: Bonjour AUF Davin (12:18:42) davin.baragiotta: on sait maintenant passer une variable aux templates! :D (12:18:44) davin.baragiotta: questions? (12:19:02) niry.andriambelo: à priori c'est ok (12:19:05) davin.baragiotta: super (12:19:20) davin.baragiotta: mais ça reste un peu nul notre truc... (12:19:23) davin.baragiotta: pourquoi? (12:19:40) davin.baragiotta: ben ma variable est "codée en dur" (hardcodée) dans ma fonction (12:19:50) davin.baragiotta: ce template affichera toujours "Davin" (12:20:01) davin.baragiotta: c'est comme si je l'avait écrit direct dans le template... non? (12:20:09) davin.baragiotta: ce qu'on veut, c'est du contenu dynamique : (12:20:27) davin.baragiotta: que le contenu s'affiche en appelant la base de données : (12:20:48) davin.baragiotta: dynamique dans le sens où le contenu de la page change si le contenu de la DB change (12:21:02) davin.baragiotta: listons nos établissements sur la page d'accueil!!! :D (12:21:13) davin.baragiotta: hmmm... comment faire? (12:21:31) davin.baragiotta: c'est là que la notion d'ORM entre en ligne de compte (12:21:36) davin.baragiotta: plan de match : (12:21:42) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (12:21:46) davin.baragiotta: je suis ici : (12:21:52) davin.baragiotta: ORM : exploration interactive (12:22:13) davin.baragiotta: ORM veut dire "object relational mapping" (12:22:15) davin.baragiotta: en fr : (12:22:32) davin.baragiotta: association des objets aux tables relationnelles de la DB (12:23:02) davin.baragiotta: les objets... sont définis dans les models.py (12:23:10) davin.baragiotta: ce sont nos Etablissement et Personne (12:23:33) davin.baragiotta: on sait qu'ils existent dans la DB... ils ont leurs tables créées avec syncdb (12:23:34) davin.baragiotta: mais (12:23:40) davin.baragiotta: on ne veut PAS faire du SQL (12:23:47) davin.baragiotta: on est des développeurs Python ;) (12:23:57) davin.baragiotta: on veut accéder aux données, sans coder de SQL (12:24:03) davin.baragiotta: l'IORM sert à ça : (12:24:11) davin.baragiotta: accéder à la DB en codant en Python (12:24:23) davin.baragiotta: l'ORM fonctionne, car nos classes, dans models.py (12:24:43) davin.baragiotta: ont hérité de models.Model.... : ce modèle parent, fournit la mécanique nécessaire pour appeler la DB (12:24:48) davin.baragiotta: testons! (12:25:22) davin.baragiotta: pour tester, on va faire comme dans l'atelier Python : explorer dans l'interpréteur, dynamiquement, interactivement (12:25:42) davin.baragiotta: on ne veut pas coder une ligne dans views.py... faire refresh... réessayer... faire refresh (12:25:44) davin.baragiotta: c'est nul (12:25:45) davin.baragiotta: donc (12:26:01) davin.baragiotta: on explore dans interpréteur... et ce qui nous plait, on le mettre dans views.py (12:26:08) davin.baragiotta: attention (12:26:28) davin.baragiotta: pour lancer interpréteur... oui on peut faire directement : ipython ou python (12:26:29) davin.baragiotta: mais (12:26:47) davin.baragiotta: tout le contexte django ne sera pas chargé... notamment les settings... (12:27:03) davin.baragiotta: bref on veut Django avc nous... donc on va lancer l'interpréteur VIA django : (12:27:09) davin.baragiotta: python manage.py shell (12:27:45) davin.baragiotta: vous avez la puissance de votre interpréteur favori qui vient d'être lancé (moi = ipython) (12:27:57) davin.baragiotta: on va importer nos modèles pour jouer avec (12:28:04) davin.baragiotta: pour appeler les données dans la DB (12:28:25) davin.baragiotta: from annuaire.models import Etablissement, Personne (12:28:44) davin.baragiotta: ok, regardez la doc de l'atelier svp (12:28:53) davin.baragiotta: etablissements = Etablissement.objects.all() (12:29:10) davin.baragiotta: sur nos classes qu'on a importé... vis "objects" (12:29:17) davin.baragiotta: c'est lui l'ORM... (12:29:31) davin.baragiotta: il nous donne accès aux "objects" de la classe Etablissement... (12:29:43) davin.baragiotta: sur objects, on a des commandes... des méthodes (12:29:54) davin.baragiotta: .all() : sélectionne tous les objets (12:29:56) davin.baragiotta: preuve (12:30:08) davin.baragiotta: on a stocké le résultat de cet appel dasn variable etablissements (12:30:14) davin.baragiotta: type(etablissements) (12:30:39) davin.baragiotta: ah, cette var est un QuerySet... c'est l'ensemble des résultats (rows) de requête à la DB ;) (12:30:45) davin.baragiotta: on peut itérer dessus (12:30:49) davin.baragiotta: faire un for (12:31:02) davin.baragiotta: for e in etablissements: print e (12:31:21) davin.baragiotta: on voit les établissemetns (12:31:22) davin.baragiotta: :D (12:31:41) davin.baragiotta: si on en veut juste le premier, pour l'explorer : (12:31:46) davin.baragiotta: e = etablissements[0] (12:31:49) davin.baragiotta: e.nom (12:31:51) davin.baragiotta: e.sigle (12:31:53) davin.baragiotta: :D (12:32:07) davin.baragiotta: ça marche? (12:32:10) davin.baragiotta: des questions? (12:32:34) shafeek.sumser: non on suit attentivement (12:32:35) davin.baragiotta: ok (12:32:39) davin.baragiotta: super :D (12:32:51) davin.baragiotta: on va essayer autre chose (12:33:02) davin.baragiotta: on va appeler directement une Personne dans la DB (12:33:13) davin.baragiotta: p = Personne.objects.get(id=1) (12:33:28) davin.baragiotta: on disait que Django ajoutait automatiquement le champs id à nos objets... (12:33:35) davin.baragiotta: là on l,utilise pour avoir la personne 1 (12:33:44) davin.baragiotta: (devrait être moi ;) ) (12:33:48) davin.baragiotta: le .get() (12:33:58) davin.baragiotta: se transforme en WHERE id=1 (12:33:59) davin.baragiotta: :D (12:34:05) davin.baragiotta: nous on code pas de SQL :D (12:34:11) davin.baragiotta: on laisse ça à eric.mcsween ;) (12:34:22) davin.baragiotta: p.id (12:34:24) davin.baragiotta: p.nom (12:34:27) davin.baragiotta: p.prenom (12:34:31) davin.baragiotta: p. + tab? (12:34:42) davin.baragiotta: quels sont les autres champs de p? (12:34:45) davin.baragiotta: type(p) (12:34:53) davin.baragiotta: ça c'est de l'introspection mes amis... (12:35:04) davin.baragiotta: bien sûr, y,a la doc Django pour nous aider... (12:35:51) davin.baragiotta: In [2]: p = Personne.objects.get(id=1) In [3]: p.id Out[3]: 1 In [4]: p Out[4]: <Personne: LEMAY Paul> In [5]: p.nom Out[5]: u'Lemay' In [6]: p.prenom Out[6]: u'Paul' In [7]: p. p.DoesNotExist p.__reduce_ex__ p._meta p.MultipleObjectsReturned p.__repr__ p._set_pk_val p.__class__ p.__setattr__ p.date_naissance p.__delattr__ p.__sizeof__ p.delete p.__dict__ p.__str__ p.id p.__doc__ p.__subclasshook__ p.nom p.__eq__ p.__unicode__ p.objects p.__format__ p.__weakref__ p.pk p.__getattribute__ p._base_manager p.prenom p.__hash__ p._collect_sub_objects p.prepare_database_save p.__init__ p._default_manager p.save p.__metaclass__ p._deferred p.save_base p.__module__ p._get_FIELD_display p.serializable_value p.__ne__ p._get_next_or_previous_by_FIELD p.universite p.__new__ p._get_next_or_previous_in_order p.universite_id p.__reduce__ p._get_pk_val (12:36:00) shafeek.sumser: id=2 = davin :D (12:36:06) davin.baragiotta: zut, c'est pas moi, c'est Paul Lemay ;) (12:36:10) davin.baragiotta: mon dummy guy ;) (12:36:23) davin.baragiotta: ok on voit aussi qu'on a un champ universite (12:36:32) davin.baragiotta: c'est le ForeignKey! (12:36:43) davin.baragiotta: allez voir annuaire/models.py, pour rappel (12:37:01) davin.baragiotta: p.universite (12:37:27) davin.baragiotta: In [7]: p.universite Out[7]: <Etablissement: Université Laval> In [8]: p.universite.sigle Out[8]: u'UL' (12:37:43) davin.baragiotta: ouah... en Python on peut chainer les appels aux objets ;) (12:37:58) davin.baragiotta: sigle de l'université de la personne (12:38:09) davin.baragiotta: finalement... (12:38:14) davin.baragiotta: y,a aussi filter() (12:38:25) davin.baragiotta: pour faire un WHERE complexe : (12:38:55) davin.baragiotta: personnes = Personne.objects.filter(nom="Baragiotta") (12:39:19) davin.baragiotta: In [9]: personnes = Personne.objects.filter(nom="Baragiotta") In [10]: personnes Out[10]: [<Personne: BARAGIOTTA Davin>] In [11]: personnes.count() Out[11]: 1 (12:39:28) davin.baragiotta: suis-je le seul a avoir ce nom? (12:39:32) davin.baragiotta: oui, dans cette DB ;) (12:39:54) davin.baragiotta: mais... ceux qui commencent avec la lettre 'B'? (12:40:19) davin.baragiotta: In [12]: personnes = Personne.objects.filter(nom__startswith="B") In [13]: personnes Out[13]: [<Personne: BARAGIOTTA Davin>] (12:40:30) davin.baragiotta: remarquez __startswith (12:40:41) davin.baragiotta: c'est des "lookup" (12:40:46) davin.baragiotta: que django offre (12:40:47) davin.baragiotta: :D (12:41:05) davin.baragiotta: on peut mettre plusieurs critères (12:41:52) davin.baragiotta: In [14]: personnes = Personne.objects.filter(nom="Baragiotta", prenom="Davin") In [15]: personnes Out[15]: [<Personne: BARAGIOTTA Davin>] In [16]: personnes = Personne.objects.filter(nom="Baragiotta", prenom="Derek") In [17]: personnes Out[17]: [] (12:42:03) davin.baragiotta: mon frère n'est pas dans la DB ;) (12:42:14) davin.baragiotta: bon dernier truc dans notre exploration de l'ORM : (12:42:20) davin.baragiotta: personnes = Personne.objects.filter(etablissement__nom__contains='Montréal') (12:42:34) davin.baragiotta: erreur (12:42:37) davin.baragiotta: je modifie la doc ;) (12:43:01) davin.baragiotta: en fait c,estlogique : je n'ai pas de champ Personne.etablissement (12:43:10) davin.baragiotta: j'ai juste Personne.universite (12:43:16) davin.baragiotta: (voir annuaire/models.py (12:43:51) davin.baragiotta: personnes = Personne.objects.filter(universite__nom__contains='Montréal') (12:44:13) davin.baragiotta: In [19]: personnes = Personne.objects.filter(universite__nom__contains='Montréal') In [20]: personnes.count() Out[20]: 2 In [21]: personnes Out[21]: [<Personne: BARAGIOTTA Davin>, <Personne: TREMBLAY Hughes>] (12:44:36) davin.baragiotta: 2 personnes sont dans une université ayant, dans son nom, le string "Montréal" (12:44:38) davin.baragiotta: :D (12:44:52) davin.baragiotta: on commence à être puissant sur les requêtes de la DB (12:44:59) davin.baragiotta: mais revenons aux choses simples : (12:45:09) davin.baragiotta: affichons sur l'accueil, la liste des établissements (12:45:18) davin.baragiotta: questions sur ORM avant de continuer? (12:45:33) niry.andriambelo: non (12:45:42) davin.baragiotta: okay (12:45:53) davin.baragiotta: codons dans views.py : (12:46:14) davin.baragiotta: appelons les établissements, exactemwent comme on l'a fait dans interpréteur (12:46:22) davin.baragiotta: et passons la variable au template (12:47:10) davin.baragiotta: from django.shortcuts import render_to_response from django.template import Context, RequestContext from carto_1_1.annuaire.models import Etablissement, Personne def home(request): variable = "Davin" etablisements = Etablissement.objects.all() c = { 'var':variable, } return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) (12:47:22) davin.baragiotta: refresh (12:47:49) davin.baragiotta: ok rien de neuf : donc pas de problème dans le code de views ;) (n'oubliez pas l'import des modèles) (12:48:15) davin.baragiotta: reste plus qu'à utiliser cette nouvelle variable dans home.html : (12:48:39) davin.baragiotta: aie... (12:48:53) davin.baragiotta: j,ai justement oublié de passer la variable en contexte au template :( (12:49:02) davin.baragiotta: c = { 'var':variable, } (12:49:04) davin.baragiotta: :( (12:49:23) davin.baragiotta: c = { 'var':variable, 'etablissements':etablissements, } (12:49:25) davin.baragiotta: :) (12:50:04) davin.baragiotta: aie... avec erreur dans nom variable : (12:50:09) davin.baragiotta: etablisements = Etablissement.objects.all() (12:50:11) davin.baragiotta: :( (12:50:16) davin.baragiotta: etablissements = Etablissement.objects.all() (12:50:18) davin.baragiotta: :) (12:50:26) davin.baragiotta: bon code final propre : (12:50:32) davin.baragiotta: from django.shortcuts import render_to_response from django.template import Context, RequestContext from carto_1_1.annuaire.models import Etablissement, Personne def home(request): variable = "Davin" etablissements = Etablissement.objects.all() c = { 'var':variable, 'etablissements':etablissements, } return render_to_response("home.html", Context(c), context_instance = RequestContext(request)) (12:50:47) davin.baragiotta: si on ajoute dans template home.html : (12:50:52) davin.baragiotta: {{ etablissements }} (12:50:55) davin.baragiotta: ça marche (12:50:58) davin.baragiotta: mais c,est laid (12:51:05) davin.baragiotta: (comme dans interpréteur) (12:51:11) davin.baragiotta: il affiche le queryset.... (12:51:24) davin.baragiotta: faut boulcer dessus.... faire un for (12:51:30) davin.baragiotta: et afficher chaque établissement (12:51:38) davin.baragiotta: aidons nous de la doc Django : (12:51:44) davin.baragiotta: https://docs.djangoproject.com/en/1.1// (12:52:03) davin.baragiotta: template layer : built-in tags and filters (12:52:04) davin.baragiotta: https://docs.djangoproject.com/en/1.1//ref/templates/builtins/#ref-templates-builtins (12:52:23) davin.baragiotta: filters, c,est comme les filtres de SPIP : |filtre() (12:52:39) davin.baragiotta: mais tags : c'est très puissant... c'est le langage de template de Django (12:52:50) davin.baragiotta: à droite... la liste de tous les tags... (12:52:52) davin.baragiotta: tiens... (12:52:54) davin.baragiotta: un for! (12:53:02) davin.baragiotta: https://docs.djangoproject.com/en/1.1//ref/templates/builtins/#for (12:53:10) davin.baragiotta: la syntaxe est : (12:53:16) davin.baragiotta: {% for ... %} (12:53:19) davin.baragiotta: pas {{ }} (12:53:21) davin.baragiotta: et (12:53:33) davin.baragiotta: faut fermer les tags avec un tag équivalent : (12:53:38) davin.baragiotta: {% endtag %} (12:53:40) davin.baragiotta: ici : (12:53:45) davin.baragiotta: {% endfor %} (12:53:58) davin.baragiotta: c'est laid... mais c'est plus du Python... (12:54:01) davin.baragiotta: ;) (12:54:04) davin.baragiotta: ok on code : (12:54:40) davin.baragiotta: {% for e in etablissements %} {{ e }} {% endfor %} (12:54:44) davin.baragiotta: refresh (12:54:55) davin.baragiotta: c'est mieux.... mais ce serait encore mieux avec du HTML (12:54:58) davin.baragiotta: une liste... (12:55:01) davin.baragiotta: ou une table (12:55:33) davin.baragiotta: <ul> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} </ul> (12:55:36) davin.baragiotta: <ul> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} </ul> (12:55:44) davin.baragiotta: ouaaaaaaaaaaah!!!! (12:56:14) davin.baragiotta: je sais que dans votre coeur... vous voyez cette liste... et vous brûlez de coder une page de détail pour chaque établissement ;) (12:56:37) davin.baragiotta: des questions sur l'utilisation réelle de l'ORM et le tag {% for %} ? (12:56:54) niry.andriambelo: non :) (12:56:58) davin.baragiotta: bon... (12:57:05) davin.baragiotta: alors regardons le plan de match (12:57:24) davin.baragiotta: en passant, reste 3 minutes à l'horaire prévu, mais on a 30 minutes de retard... (12:57:35) davin.baragiotta: j'ai l'impression qu'on a perdu des joueurs aussi ;) (12:57:54) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (12:58:02) niry.andriambelo: un autre petit point sur tech ? (12:58:30) davin.baragiotta: oui... qui suit? mettre un . sur tech (12:58:59) davin.baragiotta: ok, il y a foule (12:59:12) davin.baragiotta: nous sommes rendu à l'héritage des templates (12:59:22) davin.baragiotta: vous savez que notre page home.html (12:59:29) davin.baragiotta: n'est pas du HTML bien formé (12:59:31) davin.baragiotta: c'est mal (12:59:39) davin.baragiotta: on devrait avoir un truc du genre : (13:00:33) davin.baragiotta: <html> <head> <title>Annuaire de l'AUF</title> </head> <body> <h1>Bonjour AUF</h1> {{ var }} {{ etablissements }} <ul> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} </ul> </body> </html> (13:00:39) davin.baragiotta: html, head, title, body (13:01:11) davin.baragiotta: mais on veut *vraiment* pas coder tout ça dans cahque page de notre site (13:01:17) davin.baragiotta: c'est contre le principe DRY (13:01:27) davin.baragiotta: don't repeat yourself : ne te répètes pas (13:01:37) davin.baragiotta: alors on va centraliser le code (13:01:46) davin.baragiotta: et faire hériter nos pages avec ce code (13:01:58) davin.baragiotta: créons un template de base... nommé : base.html (13:02:08) davin.baragiotta: dans templates, à côté de home.html (13:02:38) davin.baragiotta: <html> <head> <title>Annuaire de l'AUF</title> </head> <body> </body> </html> (13:02:57) davin.baragiotta: on veut rendre le body variable... (c'est ce qui varie de page en page) (13:03:07) davin.baragiotta: on va donc décalrer un block (13:03:11) davin.baragiotta: c'est un autre tag (13:03:12) davin.baragiotta: donc : (13:03:24) davin.baragiotta: {% block main %} (13:03:29) davin.baragiotta: les tags, ça se ferme (13:03:33) davin.baragiotta: donc on ajoute : (13:03:38) davin.baragiotta: {% endblock %} (13:03:54) davin.baragiotta: <html> <head> <title>Annuaire de l'AUF</title> </head> <body> {% block main %} {% endblock %} </body> </html> (13:04:13) davin.baragiotta: ok... maintenant, on va faire hériter home.html de ce template de base : (13:04:16) davin.baragiotta: home.html : (13:04:19) davin.baragiotta: en haut : (13:04:29) davin.baragiotta: {% extends "base.html" %} (13:04:52) davin.baragiotta: et finalement (13:05:09) davin.baragiotta: on va dire que le contenu qu'on avait dans home.html... ben il va dans le block main (13:05:34) davin.baragiotta: {% extends "home.html" %} {% block main %} <h1>Bonjour AUF</h1> {{ var }} {{ etablissements }} <ul> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} </ul> {% endblock %} (13:05:49) davin.baragiotta: faites un refresh de / (13:06:07) davin.baragiotta: aaaah (13:06:09) davin.baragiotta: erreur (13:06:14) davin.baragiotta: récursion ;) (13:06:19) davin.baragiotta: {% extends "home.html" %} (13:06:23) davin.baragiotta: base.html (13:06:24) davin.baragiotta: ;) (13:06:34) davin.baragiotta: {% extends "base.html" %} {% block main %} <h1>Bonjour AUF</h1> {{ var }} {{ etablissements }} <ul> {% for e in etablissements %} <li>{{ e }}</li> {% endfor %} </ul> {% endblock %} (13:06:43) davin.baragiotta: ok (13:06:52) davin.baragiotta: regardez les sources de la page : ctrl+u (13:07:11) davin.baragiotta: excellent... les balises sont bien là ;) (13:07:23) davin.baragiotta: c'était l'héritage des templates ;) (13:07:24) davin.baragiotta: :D (13:07:39) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (13:07:49) davin.baragiotta: créons maintenant une page de détail... (13:07:55) davin.baragiotta: là on n'est plus dans la config... (13:08:01) davin.baragiotta: on est dans du vrai développement (13:08:22) davin.baragiotta: quand votre directeur vous dit "ouais ce serait bien une page qui fait ça" ;) (13:08:28) davin.baragiotta: donc on ajoute les pages... ;) (13:08:35) davin.baragiotta: quel processus suivre? (13:08:47) davin.baragiotta: on codons en suivant le flux d'exécution : (13:09:01) davin.baragiotta: urls.py > views.py > templates (13:09:14) davin.baragiotta: codons une page de détail pour un établissement (13:09:27) davin.baragiotta: (on veut tout voir ce qu'on sait sur cet établissemetn) (13:09:32) davin.baragiotta: commençons par urls.py (13:09:54) davin.baragiotta: ajoutons une règle en copiant celle du home (13:10:05) davin.baragiotta: ah... mieux... minute (13:10:34) davin.baragiotta: enfin non copions (13:10:53) davin.baragiotta: il fautr miantenant choisir une URL pour le détail d'un établissent (13:11:13) davin.baragiotta: on veut de belles URLs, c'Est important en 2012... et on fait pas du PHP ;) (13:11:14) davin.baragiotta: (oups) (13:11:35) davin.baragiotta: http://127.0.0.1:8000/etablissements/123 (13:11:39) davin.baragiotta: par exemple? (13:11:52) davin.baragiotta: on pourrait discuter si on met au pluriel ou pas... (13:12:05) davin.baragiotta: mais par convention, adns URL, on met au pluriel (13:12:08) davin.baragiotta: donc (13:12:28) davin.baragiotta: url(r'^etablissements/123$', 'carto_1_1.views.home', name='home'), (13:12:35) davin.baragiotta: on peut changer son nom, déjà... (13:12:42) davin.baragiotta: c'est la page détail d'un établissement : (13:12:50) davin.baragiotta: etablissement_detail (13:13:02) davin.baragiotta: url(r'^etablissements/123$', 'carto_1_1.views.home', name='etablissement_detail'), (13:13:06) davin.baragiotta: ok... (13:13:13) davin.baragiotta: mais là... 123 c'est une constante... (13:13:23) davin.baragiotta: ça veut dire que si tu mets pas 123 ça amrche (13:13:24) davin.baragiotta: pas (13:13:42) davin.baragiotta: et surtout... on veut que ça varie pour chaque etablissement... (13:14:04) davin.baragiotta: là, faut connaitre les regex.... et moi je copie-colle toujours car de tête c'est pas évident : (13:14:38) davin.baragiotta: minute, je donne la solution : (13:15:25) davin.baragiotta: url(r'^etablissement/(?P<id>\d+)$', 'carto_1_1.views.home', name="etablissement"), (13:15:27) davin.baragiotta: bon (13:15:35) davin.baragiotta: le pattern se lit ainsi : (13:16:29) davin.baragiotta: si y'a une groupe () qui a un ou plus + digits \d.... alors capte ce groupe dans une param ?P nommé id <id> (13:16:31) davin.baragiotta: ouais, bon... (13:16:33) davin.baragiotta: ;) (13:16:38) davin.baragiotta: finalement (13:16:50) davin.baragiotta: reste que la fonction appelée à changer.... (13:16:57) davin.baragiotta: reste 15 minutes... (13:17:14) davin.baragiotta: je vais vous montrer tout ça, si vous permettez, (avec autres choses)... dans le code final (13:17:17) davin.baragiotta: d'accord? (13:17:35) davin.baragiotta: nous resterait à coder la views.py et le template html... (13:17:36) niry.andriambelo: d'accord (j'imagine) (13:17:38) niry.andriambelo: :) (13:17:41) davin.baragiotta: on fait un saut dans le temps! (13:17:47) davin.baragiotta: ouais, on est d'accord ;) (13:18:12) davin.baragiotta: voici les sources finales à télécharger et extraire... attention, ça s'appelle aussi carto_1_1 (13:18:21) davin.baragiotta: désolé, j'organiserai mieux : (13:18:37) davin.baragiotta: http://git.auf.org/?p=davin.git;a=snapshot;h=0f355ca952ddf8f9c7636226904a5fcb04ee53dc;sf=tgz (13:19:21) davin.baragiotta: c'est davin-0f355ca/ateliers/django/carto_1_1 (13:19:28) davin.baragiotta: qui nous intéresse (13:19:44) davin.baragiotta: je le mets direct dans mon home (13:20:19) davin.baragiotta: davin.baragiotta@u-db:~/carto_1_1$ ls annuaire carto.db __init__.py manage.py media settings.py templates urls.py views.py (13:20:22) davin.baragiotta: ok mes amis... (13:20:30) davin.baragiotta: attention au clou de la journée (13:20:31) shafeek.sumser: oui pareil comme indiqué (13:20:40) davin.baragiotta: le feu d'artifice Django : (13:20:47) davin.baragiotta: python manage.py runserver (13:20:53) davin.baragiotta: (fermer l'autre avant...) (13:21:32) davin.baragiotta: http://127.0.0.1:8000/ (13:21:36) davin.baragiotta: tadaaaaaaaaaaaaaaaaaaaaam!!!! (13:22:00) davin.baragiotta: on l'a tous? (13:22:44) davin.baragiotta: ok ce code = le code final des 2 ateliers backend et frontend (13:22:55) davin.baragiotta: vous pouvez voir annuaire/admin.py (13:23:03) davin.baragiotta: et tester dans l'admin : les filtres à droite... (13:23:09) davin.baragiotta: la recherche dans Personne (13:23:16) davin.baragiotta: les colonnes dans les listings (13:23:20) davin.baragiotta: rien de sorcier ;) (13:23:24) davin.baragiotta: mais très utile... (13:23:47) davin.baragiotta: pour cet atelier frontend : couvrons rapidement les nouveautés de ce code (13:23:54) davin.baragiotta: 1. les URLs avec param (13:24:00) davin.baragiotta: ce qu'on avait commencé à codé... (13:24:06) davin.baragiotta: je vous montre dans : urls.py (13:24:19) davin.baragiotta: # annuaire (r'^', include('carto_1_1.annuaire.urls')), (13:25:01) davin.baragiotta: en fait... toutes les URL qui ne matchent pas dans urls.py.... on les envoient tester dans annuaire.urls (13:25:06) davin.baragiotta: annuaire.urls.py : (13:25:21) davin.baragiotta: # -*- encoding: utf-8 -*- from django.conf.urls.defaults import patterns, include, url urlpatterns = patterns('carto_1_1.annuaire.views', # établissements url(r'^etablissements$', 'etablissement_list', name="etablissements"), url(r'^etablissement/(?P<id>\d+)$', 'etablissement_detail', name="etablissement"), # personnes url(r'^personnes$', 'personne_list', name="personnes"), url(r'^personne/(?P<id>\d+)$', 'personne_detail', name="personne"), ) (13:25:26) davin.baragiotta: pareil que urls.py (13:25:34) davin.baragiotta: url(r'^etablissement/(?P<id>\d+)$', 'etablissement_detail', name="etablissement"), (13:25:40) davin.baragiotta: c'est ce qu'on codait... (13:25:49) davin.baragiotta: url(r'^etablissements$', 'etablissement_list', name="etablissements"), (13:25:58) davin.baragiotta: tiens... la liste complète des établissements (13:26:03) davin.baragiotta: essayons cette URL : (13:26:13) davin.baragiotta: ilen établissemetns dans interface : (13:26:14) davin.baragiotta: http://127.0.0.1:8000/etablissements (13:26:33) davin.baragiotta: super avec un lien sur chaque (13:26:40) davin.baragiotta: on clique sur un établissement (13:26:45) davin.baragiotta: http://127.0.0.1:8000/etablissement/1 (13:27:05) davin.baragiotta: on suit le traitement de l'info : urls.py > annuaire/urls.py > (13:27:31) davin.baragiotta: puis annuaire/views.py (préfixe de tous mes pattenrs : 'carto_1_1.annuaire.views' ) (13:27:46) davin.baragiotta: et on cherche fonction 'etablissement_detail' (13:27:54) davin.baragiotta: lisons views.py (13:28:01) davin.baragiotta: dans annuaire (13:28:09) davin.baragiotta: def etablissement_detail(request, id): etablissement = Etablissement.objects.get(id=id) c = { 'etablissement': etablissement, } return render_to_response("annuaire/etablissement_detail.html", Context(c), context_instance = RequestContext(request)) (13:28:22) davin.baragiotta: on ajoute le paramètre id capté par pattern url (13:28:23) davin.baragiotta: :) (13:28:29) davin.baragiotta: on fait un .get() (13:28:35) davin.baragiotta: comme vu en explorant l'ORM (13:28:43) davin.baragiotta: on passe l'établissement au template (13:28:50) davin.baragiotta: annuaire/etablissement_detail.html (13:29:12) davin.baragiotta: on a un répertoire templates dans l'app annuaire : (13:29:15) davin.baragiotta: ouvrons (13:29:47) davin.baragiotta: carto_1_1/annuaire/templates/annuaire/etablissement_detail.html (13:29:57) davin.baragiotta: violà... (13:30:03) davin.baragiotta: on sait tout faire ça : (13:30:06) davin.baragiotta: {{ }} (13:30:10) davin.baragiotta: {% for %} (13:30:16) davin.baragiotta: reste juste tag {% url (13:30:18) davin.baragiotta: un mot : (13:30:35) davin.baragiotta: sont but = générer l'URL complète à partir des noms de noms patterns d'URL : (13:30:38) davin.baragiotta: ;D (13:30:41) davin.baragiotta: :D (13:30:49) davin.baragiotta: <li><a href="{% url personne p.id %}">{{ p }}</a></li> (13:30:50) davin.baragiotta: se lit : (13:31:22) davin.baragiotta: génère moi l'URL complète de l'URL gérée par le pattern nommé "personne"... et je te passe le id du p en cours (13:31:24) davin.baragiotta: p.id (13:31:28) davin.baragiotta: ça donne ceci (13:31:35) davin.baragiotta: http://127.0.0.1:8000/personne/2 (13:31:46) davin.baragiotta: car on a ce pattern nommé "personne" (13:31:57) davin.baragiotta: url(r'^personne/(?P<id>\d+)$', 'personne_detail', name="personne"), (13:32:06) davin.baragiotta: dans annuaire/urls.py (13:32:15) davin.baragiotta: ça s'appelle faire du reverse url (13:32:18) davin.baragiotta: voilà (13:32:29) davin.baragiotta: quaoi d'autres.... explorez rapido les interfaces : (13:32:35) davin.baragiotta: on a de la mécanique de connexion (13:32:43) davin.baragiotta: c'est simple : (13:32:56) davin.baragiotta: urls.py, settings.py + connexion.html et deconnexion.html (13:33:01) davin.baragiotta: testez, ça marche! (13:33:07) davin.baragiotta: user : admin, pass : admin (13:33:13) shafeek.sumser: testé (13:33:26) davin.baragiotta: avec lien vers admin en haut, of course ;) (13:33:28) davin.baragiotta: bon voilà (13:33:40) davin.baragiotta: regardons ce qui manque dans plan de match : (non couvert) (13:33:53) davin.baragiotta: https://wiki.auf.org/wikiteki/Ateliers/Django/Frontend/Support (13:34:07) davin.baragiotta: ah oui... la magie du design (13:34:12) davin.baragiotta: tout est dans : (13:34:20) davin.baragiotta: répertoire /media/... css et images (13:34:34) davin.baragiotta: settings.py dit où se trouve les media : MEDIA_URL (13:34:53) davin.baragiotta: et le template de base... base.html... vraiment étoffé... utilise ces styles : {{ MEDIA_URL }} (13:35:09) davin.baragiotta: finissons avec les sources de base.html : (13:35:10) davin.baragiotta: ;) (13:35:30) davin.baragiotta: ça... on veut pas coder ça dans toutes nos pages! (13:35:45) davin.baragiotta: un chance qu'on a un framework de développement qui offre héritage de template! (13:35:51) davin.baragiotta: c'était l,atelier sur frontend (13:36:02) davin.baragiotta: vous savez maintenant monter des interfaces web avec Django (13:36:14) davin.baragiotta: pour afficher au public les données gérées dans l'admin (13:36:20) davin.baragiotta: des questions? (13:36:46) niry.andriambelo: shafeek.sumser: Q: par contre le base.html se situe dans le dossier racine du projet! (13:37:02) niry.andriambelo: mais je viens de verifier c'est bien dans templates pour moi (13:37:27) davin.baragiotta: (13:36:59) giotta: ouais... l'app reste couplée... tout ne peut pas être 100% coupé (13:37:12) giotta: mais c'est pas la job de l'app de décider du design global ;) (13:38:11) davin.baragiotta: oui, shafeek.sumser a raison : carto_1_1/templates/base.html (13:38:27) davin.baragiotta: utilisé par les templates de carto_1_1/annuaire/templates/... (13:38:28) davin.baragiotta: ;) (13:39:02) davin.baragiotta: mais en gros : c,est un détail de design génie logiciel... mais tout réorganiser c'est très facile, si on n,est pas content ;) (13:39:23) davin.baragiotta: ----------------------- FIN ATELIER DJANGO : frontend ---------------------------