"…mais ce serait peut-être l'une des plus grandes opportunités manquées de notre époque si le logiciel libre ne libérait rien d'autre que du code…"

Archive for 17 juillet 2007

Une application Web Django (GET)…

Posted by patrick le juillet 17, 2007

Mon précédent billet (http://pvergain.wordpress.com/2007/07/11/restful-resource-oriented-architecture-roa-http-xml/) devenant trop long je continue ici la dernière partie concernant Django.

Le titre du billet est ‘Une application Web Django (GET)...’ . Je n’ai pas mis le terme RESTful car une application Web à l’heure actuelle (juillet 2007) avec les normes HTML4 ou XHTML 1 ne peut utiliser d’autres méthodes HTTP que GET et POST ==> elle n’est donc pas RESTful.

Références pour ce problème méconnu:

  • http://cafe.elharo.com/web/why-rest-failed/ ("The problem is that GET, PUT, POST, and DELETE really are a minimal set. You truly do need all four, and we only have two; and I’ve never understood why. In 2006 browser vendors still don’t support PUT and DELETE. A few browsers over the years have tried to implement these as parts of editing functionality, but they’ve never allowed it in a real web application as opposed to a thick client GUI. The method of an HTML form is limited to GET and POST. PUT and DELETE are not allowed. This isn’t some failure of browser vendors to properly implement the specification either. The HTML specification only allows GET and POST as form actions. XHTML and even XForms 1.0 don’t change this. This means it’s impossible to build a fully RESTful client application inside a web browser. Consequently everyone tunnels everything through POST, and simply ignores PUT and DELETE")
  • http://www.biologeek.com/journal/index.php/pour-ne-plus-etre-en-rest-comprendre-cette-architecture ("Les applications web utilisent HTTP pour permettre au serveur et au client de communiquer ensemble. … Que se passe-t-il vraiment lorsque vous tapez une adresse dans votre navigateur ? Le navigateur met en forme un message HTTP pour appeler la méthode GET de la ressource identifiée par l’URL que vous lui avez fourni. Vous pouvez aussi appeler la méthode POST à partir de votre navigateur – mais seulement s’il y a un formulaire <form> sur la page. (Ok, pas exactement grâce à AJAX mais oublions pour le moment). Les formulaires peuvent envoyer des données à une URL particulière. Lorsque vous soumettez un formulaire, le navigateur appelle la méthode POST, passant l’URL ainsi que certaines données représentant la ressource qu’il doit ajouter ou modifier. Vous ne pouvez pas appeler PUT ou DELETE avec votre navigateur avec du HTML habituel")
  • http://groups.google.com/group/django-developers/browse_thread/thread/4278ea1ad73f68f1/e754aa3a5a4fcca2 ("but what is the recommended way to handle fake PUT and DELETE from a browser? The HttpMethodMiddleware ? Maybe a simple form/deletion in the polls application will be an interesting example for a real django case")
  • http://www.w3.org/TR/html401/interact/forms.html#adef-method ("method = get|post [CI] This attribute specifies which HTTP method will be used to submit the form data set. Possible (case-insensitive) values are "get" (the default) and "post". See the section on form submission for usage information")
  • http://www.whatwg.org/specs/web-forms/current-work/#methodAndEnctypes ("The HTTP specification defines various methods that can be used with HTTP URIs. Four of these may be used as values of the method attribute: get, post, put, and delete. In this specification, these method names are applied to other protocols as well. This section defines how they should be interpreted")

Comme on travaille sur la version de développement, on fait la mise à jour de django (cd ~/django_src; svn update):

pve@pc72 ~/django_src
$ cd ~/django_src; svn update
U django/test/client.py
U django/db/backends/postgresql_psycopg2/introspection.py
U django/conf/locale/de/LC_MESSAGES/djangojs.mo
U django/conf/locale/de/LC_MESSAGES/djangojs.po
U django/conf/locale/es_AR/LC_MESSAGES/django.po
U django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
U django/conf/locale/es_AR/LC_MESSAGES/django.mo
U django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
U django/conf/locale/fr/LC_MESSAGES/djangojs.mo
U django/conf/locale/fr/LC_MESSAGES/djangojs.po
U django/conf/locale/zh_CN/LC_MESSAGES/django.po
U django/conf/locale/zh_CN/LC_MESSAGES/django.mo
U django/conf/locale/es/LC_MESSAGES/django.po
U django/conf/locale/es/LC_MESSAGES/djangojs.mo
U django/conf/locale/es/LC_MESSAGES/django.mo
U django/conf/locale/es/LC_MESSAGES/djangojs.po
U django/conf/project_template/settings.py
U django/conf/__init__.py
U django/conf/global_settings.py
U django/core/servers/basehttp.py
U django/core/urlresolvers.py
U django/core/validators.py
U django/core/management.py
U django/core/cache/backends/locmem.py
U django/newforms/fields.py
U django/contrib/comments/templatetags/comments.py
U django/contrib/admin/media/js/admin/RelatedObjectLookups.js
U django/contrib/admin/templatetags/admin_list.py
U django/contrib/admin/views/main.py
U django/contrib/localflavor/no/forms.py
U django/contrib/sessions/middleware.py
U django/utils/cache.py
U django/utils/html.py
U django/bin/make-messages.py
U django/template/defaultfilters.py
U django/middleware/common.py
U django/middleware/http.py
U tests/modeltests/str/models.py
U tests/regressiontests/forms/tests.py
U tests/regressiontests/forms/localflavor.py
A tests/regressiontests/utils
A tests/regressiontests/utils/__init__.py
A tests/regressiontests/utils/tests.py
A tests/regressiontests/utils/models.py
U tests/regressiontests/cache/tests.py
U AUTHORS
U docs/db-api.txt
U docs/newforms.txt
U docs/testing.txt
U docs/django-admin.txt
U docs/templates.txt
Updated to revision 5717.

Ensuite, on peut lancer le serveur HTTP django:

$ cd /cygdrive/e/projets/pybookmarks/; python manage.py runserver
Validating models…
0 errors found.

Django version 0.97-pre, using settings ‘pybookmarks.settings’
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

En naviguant sur l’interface d’administration, je m’aperçois qu’il faut installer la bibliothèque docutils ("Docutils is an open-source text processing system for processing plaintext documentation into useful formats, such as HTML or LaTeX. It includes reStructuredText, the easy to read, easy to use, what-you-see-is-what-you-get plaintext markup language")

Docutils

Je le télécharge au moyen de la commande ‘svn checkout http://svn.berlios.de/svnroot/repos/docutils/trunk/docutils docutils docutils" puis je tape la commande suivante: "cd docutils; python setup.py install"

J’arrête le serveur (Ctrl+C) , je le relance (python manage.py runserver) et cette fois j’ai bien la documentation en ligne à partir du site d’administration.

Docutils

Maintenant on peut continuer à expliquer toutes les lignes du fichier ‘urls.py’: On en est à la partie 3 du tutorial django (This tutorial begins where Tutorial 2 left off. We’re continuing the Web-poll application and will focus on creating the public interface — “views.”, http://www.djangoproject.com/documentation/tutorial03/)

#!/usr/bin/python
# -*- coding: UTF-8 -*-

"""
If you need help with regular expressions, see Wikipedis entry
(http://en.wikipedia.org/wiki/Regular_expression)
and the Python documentation. (http://www.python.org/doc/current/lib/module-re.html)
Also, the O’Reilly book Mastering Regular Expression by Jeffrey Friedl is fantastic.

/cygdrive/e/projets/pybookmarks/urls.py
"""

from django.conf.urls.defaults import *
from bookmarks.views import *

urlpatterns = patterns(",
(r’^users/([\w-]+)/$’, bookmark_list),
(r’^users/([\w-]+)/tags/$’, tag_list),
(r’^users/([\w-]+)/tags/([\w-]+)/’, tag_detail),
(r’^users/([\w-]+)/(.+)’, BookmarkDetail()),
(r’^admin/’, include(‘django.contrib.admin.urls’)),
)

L’expression: r’^users/([\w-]+)/$’ est une expression rationnelle (Pour travailler avec les expressions rationnelles, un outil graphique tel que Kodos est vraiment très pratique)

Cette expression identifie une des chaines suivantes

  • users/chomsky
    • Kodos

On l’utilise dans la navigateur Web de cette façon: http://127.0.0.1:8000/users/chomsky

Dans l’exemple du livre ‘RESTful Web Services’ on ne sert pas une page au format HTML mais au format JSON. Je vais donc modifier le fichier ‘ /cygdrive/e/projets/pybookmarks/bookmarks/views.py’ pour servir une page HTML. On étudiera donc les objets django.template (voir http://www.djangoproject.com/documentation/templates, Django’s template language is designed to strike a balance between power and ease. It’s designed to feel comfortable to those used to working with HTML. If you have any exposure to other text-based template languages, such as Smarty or CheetahTemplate, you should feel right at home with Django’s templates.).

Django template

Il faut créer la hiérarchie suivante:

template bookmarks

On crée le fichier template E:/projets/pybookmarks/bookmarks/template/bookmarks/index.html qui contient les lignes suivantes:

{% if latest_bookmark_list %}
<ul>
{% for bookmark in latest_bookmark_list %}
<li>{{ bookmark.url }}</li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks are available.</p>
{% endif %}

On ajoute les lignes suivantes au fichier views.py:

from django.template import Context, loader

on modifie la fonction "bookmark_list(request, username):"


t=loader.get_template(‘bookmarks/index.html’)
c=Context({‘latest_bookmark_list’: marks})

response = HttpResponse(t.render(c))

On modifie le fichier settings.py:

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.
"E:/projets/pybookmarks/bookmarks/template",
)

Et voilà ce que ça donne (j’avais auparavant introduit quelques bookmarks au moyen de l’interface administrateur http://127.0.0.1:8000/admin)

Bookmarks chomsky

Si on regarde le code source de la page on a:

     <ul>

        <li>http://www.chomsky.info/</li>

        <li>http://www.chomsky.info/audionvideo.htm</li>

        <li>http://people.csail.mit.edu/meyer/iandc-WWW/Authors/chomskynoam.html</li>

    </ul>

Ce qui est bien l’instanciation du fichier template E:/projets/pybookmarks/bookmarks/template/bookmarks/index.html

Pour l’instant notre document n’est donc pas du tout conforme aux standards du Web (emploi de XHTML, emploi des feuilles de style CSS, emploi des normes de l’accessibilité du Web). Ce sont des sujets que nous verrons un peu plus tard.

Revenons à notre problème de PUT et DELETE. Dans le fichier /cygdrive/e/projets/pybookmarks/urls.py on a la ligne suivante: (r’^users/([\w-]+)/(.+)’, BookmarkDetail()). Elle permet de lire le détail d’une URL, de détruire une URL ou de créer une URL.

On va d’abord faire un test sur ‘GET’. Je modifie le fichier /cygdrive/e/projets/pybookmarks/bookmarks/views.py pour servir du HTML plutôt que du JSON.

Je modifie la méthode BlogmarkDetail.do_GET():

t=loader.get_template(‘bookmark/index.html’)
c=Context({‘mark’: bookmark,’request’: self.request})
return HttpResponse(t.render(c))

Je crée le fichier ‘bookmark/index.html’:

{% if mark %}
<ul>
<li> {{mark.url}} </li>
<li> {{mark.user}} </li>
<li> {{mark.long_description}} </li>
</ul>
<p> La requete: </p>
<ul>
<li> Request.method={{request.method}}</li>
<li> Request.raw_post_data={{request.raw_post_data}}</li>
</ul>
{% else %}
<p>pas de bookmark.</p>
{% endif %}

Je n’ai pas àmodifier le fichier # /cygdrive/e/projets/pybookmarks/bookmarks/settings.py

Je teste avec l’URL: http://127.0.0.1:8000/users/chomsky/http://www.chomsky.info/ et j’obtiens la page HTML suivante:

Get request

Voilà pour notre premier verbe HTTP: ‘GET’.

Pour ‘POST’ nous devons passer par un formulaire (form) et c’est ce que nous verrons dans le prochain billet en étudiant le tutorial 04 (http://www.djangoproject.com/documentation/tutorial04/, "This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on simple form processing and cutting down our code").

Posted in python, REST | Leave a Comment »

 
Suivre

Recevez les nouvelles publications par mail.

Rejoignez 79 autres abonnés