Canalblog
Suivre ce blog Administration + Créer mon blog

Django Spirit

1 septembre 2012

Déménagement !

Bon ! Assez rigolé ! Un blog c'est bien sympa pour être référencé et connu rapidement... Mais ce n'est franchement pas pratique pour y présenter une doc de façon un tant soit peu sérieuse ! Donc, on déménage ! Retrouvez la doc de Django Framework, traduite...
Publicité
Publicité
3 novembre 2012

Django Framework : Travailler avec des formulaires

À propos de ce document

Ce document fournit une introduction aux fonctions Django de gestion de formulaire. Pour plus de détails sur des domaines plus spécifiques de l’API Formulaires, voir The Forms API, Form fields, et Form and field validation.

django.forms est la biliothèque Django de gestion de formulaires.

Bien qu’il soit possible de traiter la soumission des formulaires en n’utilisant que la classe HttpRequest de Django, utiliser la bibliothèque de formulaires permet la prise en charge de nombre d’opérations relatives aux formulaires. En l’utilisant, vous pouvez:

  1. Afficher un formulaire HTML avec des widgets générés automatiquement.
  2. Vérifier les données envoyées, grâce à un ensemble de règles de validation.
  3. Ré-afficher une formulaire en cas d’erreurs de validation.
  4. Convertir les données du formulaire envoyé en types de données Python pertinentes.

Aperçu

La bibliothèque couvre ces concepts:

Widget
Une classe qui correspond à un widget de formulaire HTML, par exemple, <input type="text"> ou <textarea>. Gère le rendu du widget en HTML.
Field
Une classe responsable de la validation. Par exemple, un EmailField s’assure qu’on indique bien une adresse e-mail valide.
Form
Une collection de champs qui savent se valider eux-mêmes et s’afficher sous forme HTML.
Form Media
Les ressources CSS et JavaScript requises pour produire le formulaire.

La bibliothèque est découplée des autres composants Django, comme la couche de base de données, les vues et les templates. Elle n’est liée qu’aux paramètres Django, à quelques fonctions d’assistance django.utils et aux hooks d’internationalisation de Django (mais vous n’êtes pas obligé d’utiliser les fonctionnalités d’internationalisation pour utiliser cette bibliothèque).


 

La traduction complète en français se trouve sur DjangoSpirit.org.

3 novembre 2012

Le langage de template de Django

A propos de ce document

Ce document explique la syntaxe du système de mise en page de Django. Si vous recherchez une approche plus technique sur son fonctionnement et sur son extension, voyez The Django template language: For Python programmers.

Le langage de mise en page de Django est conçu pour allier puissance et facilité d’utilisation. Il est conçu pour que les personnes habituées à travailler avec le HTML se sentent à l’aise. Si vous avez déjà utilisé d’autres langages de mise en page, comme Smarty ou CheetahTemplate, vous devriez vous sentir comme chez vous avec les templates Django.

Philosophie

Si vous avez une formation en programmation, ou si vous êtes habitué à des langages comme PHP qui mélangent directement du code-source PHP à du HTML, vous devez avoir à l’esprit que le système de mise en page de Django n’est pas simplement du Python incorporé à du HTML. C’est intentionnel : le système de template est là pour présenter et mettre en forme les données, pas pour exposer la logique du programme.

Le système de template de Django fournit des balises (tags) qui fonctionnent de manière similaire à certaines constructions de programmation – une balise if pour les tests booléens, une balise for pour les boucles, etc. – mais elles ne sont pas simplement exécutées comme le code Python équivalent, et le système de template n’exécutera pas des expressions Python arbitraires. Seuls les balises, les filtres et la syntaxe énumérés ci-dessous sont prises en charge par défaut (bien que vous puissiez ajouter your own extensions au langage de template, si nécessaire).

 


 

La traduction complète en français se trouve sur DjangoSpirit.org.

2 novembre 2012

Répartiteur d'URl (URL dispatcher)

Traduction française de la page  "URL dispatcher" de Django publiée ce jour : http://www.djangospirit.org/topics/http/urls.html

14 septembre 2012

Django : syntaxe des modèles

Publication dela traduction de la doc Django : Syntaxe de modèles, sur DjangoSpirit.org.

Publicité
Publicité
31 août 2012

Reprise des publications des traductions...

Ouh la ! C'est lessivant de traduire les tutos Django en français... Et quelle audience en plus ! :-)

 

Bon ! J'ignore dans quoi je me suis engagé...

 

Alors, si tout va bien, retour vers le 6 ou 7 septembre (2012).

 

A+ ! :-)

 

 


31 août 2012

Tuto « Première appli Django », partie 4

Écrire votre première application Django, partie 4

Ce tuto commence là où le Tutorial 3 se termine. On poursuit avec l'application web Sondages et on va aborder le traitement des formulaires simples et la réduction de code.

Écrire un formulaire simple

Actualisons le template détail de sondage (“polls/detail.html”) vu dans le dernier tuto, pour qu'il contienne un élément HTML

:

{{ poll.question }}
{% if error_message %}

 

{{ error_message }}{% endif %}
<form action="/polls/{{ poll.id }}/vote/" method="post">
{% csrf_token %}
{% for choice in poll.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice }}<br />
{% endfor %}
<input type="submit" value="Vote" />

Un bref aperçu :

  • Ce template affiche un bouton radio pour chaque choix de sondage. La valeur value de chaque bouton radio est l'ID du choix du sondage. Le name de chaque bouton radio est "choice". Cela veut dire que quand quelqu'un sélectionne l'un des boutons radio et valide le formulaire, les données POST choice=3 seront envoyées. C'est un formulaire HTML Forms 101.
  • Nous paramètrons l'action du formulaire à /polls/{{ poll.id }}/vote/, et nous paramétrons method="post". Il est important d'utiliser method="post" (par opposition à method="get") parce que le fait de valider ce formulaire va modifier des données côté serveur. Chaque fois que vous créez un formulaire qui modifie des données côté serveur, utilisez method="post". Ce n'est pas spécifique à Django, c'est juste une bonne pratique de développement WEB.
  • forloop.counter indique combien de fois la balise for est passée dans la boucle.
  • Puisque nous créons un formulaire POST (qui a pour conséquence la modification de données), nous devons nous prémunir contre les attaques Cross Site Request Forgeries. Heureusement, vous n'avez pas trop à vous en préoccuper car Django dispose d'un système facile à utiliser pour s'en protéger. Pour résumer : tous les formulaires POST qui sont ciblés comme des URL internes doivent utiliser la balise de template {% csrf_token %}.

La balise {% csrf_token %} exige des informations de l'objet request, qui ne sont normalement pas accessibles depuis le contexte template. Pour arranger ça, une petite modif doit être faite à la vue detail, pour qu'elle ressemble à ça :

from django.template import RequestContext
# ...
def detail(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/detail.html', {'poll': p},
context_instance=RequestContext(request))

Le détail de ce fonctionnement est expliqué dans la documentation de RequestContext.

Créons maintenant une vue Django qui gère les données envoyées et en fait quelque chose. Rappelez-vous, dans le Tutorial 3, nous avons créé un URLconf pour l'application sondages qui comportait cette ligne :

(r'^(?P<poll_id>\d+)/vote/$', 'vote'),

Nous avons aussi créé une implémentation factice de la fonction vote(). Créons la version réelle. Ajoutez ce qui suit à polls/views.py :

from django.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.template import RequestContext
from polls.models import Choice, Poll
# ...
def vote(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
try:
selected_choice = p.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Réaffiche le formulaire de vote de sondage.
return render_to_response('polls/detail.html', {
'poll': p,
'error_message': "You didn't select a choice.",
}, context_instance=RequestContext(request))
else:
selected_choice.votes += 1
selected_choice.save()
# Toujours renvoyer un HttpResponseRedirect après avoir réussi à gérer 
# les données POST. Cela évite de poster deux fois les données si un
# utilisateur clique sur le bouton Arrière.
return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,)))

Ce code comporte quelques petites choses qui n'ont pas encore été abordées dans ce tuto :

  • request.POST est un objet dictionary-like qui vous permet d'accéder aux données via le nom des clés. Dans ce cas, request.POST['choice'] renvoie l'ID du choix sélectionné, comme chaîne. Les valeurs request.POST sont toujours des chaînes.

    Notez que Django fournit également request.GET pour accéder aux données GET de la même façon -- mais nous utilisons request.POST explicitement dans notre code, pour nous assurer que les données ne sont modifiées que par un appel POST.

  • request.POST['choice'] lévera une erreur KeyError si choice n'a pas été fourni dans les données POST. Le code précédent vérifie la présence de KeyError et réaffiche le formulaire avec un message d'erreur si choice n'a pas été fourni.

  • Après avoir incrémenté le décompte de choice, le code retourne un HttpResponseRedirect plutôt que le HttpResponse habituel. HttpResponseRedirect prend un seul argument : l'URL vers laquelle sera redirigé l'utilisateur (voir le point suivant pour la construction de l'URL dans ce cas de figure).

    Comme le signale le commentaire Python, vous devriez toujours retourner un HttpResponseRedirect après avoir réussi le traitement des données POST. Ce n'est pas propre à Django, c'est simplement une bonne pratique de développement Web.

  • Dans cet exemple, nous utilisons la fonction reverse() dans le constructeur HttpResponseRedirect. Cette fonction nous aide à éviter de coder l'URL en dur dans la fonction de vue. On lui donne le nom de la vue à laquelle nous voulons passer la main et la position de la variable dans le motif d'URL qui pointe sur cette vue. Dans ce cas, en utilisant l'URLconf paramétré dans le tuto 3, l'appel à reverse() retournera une chaîne comme

    '/polls/3/results/'
    

    ... où 3 est la valeur de p.id. Cette URl redirigée appellera alors la vue 'results'pour afficher la page finale. Notez que vous devrez utiliser ici le nom complet de la vue (y compris son préfixe).

Comme mentionné dans le Tutorial 3, request est un objet HttpRequest. Pour en savoir plus sur les objets HttpRequest, consultez la doc request and response documentation.

Après que quelqu'un vote dans le sondage, la vue vote() redirige vers la page de résultats du sondage. Écrivons cette vue :

def results(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/results.html', {'poll': p})

C'est exactement la même chose que pour la vue class="docutils literal">detail() du Tutorial 3. La seule différence réside dans le nom du template. Nous réparerons cette redondance plus tard.

Maintenant, créons un template results.html :

{{ poll.question }}

{% for choice in poll.choice_set.all %}
{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
{% endfor %}

<a href="/polls/{{ poll.id }}/">Vote again?

Maintenant, allez dans /polls/1/ avec votre navigateur et votez dans le sondage. Vous devriez voir une page de résultats qui est actualisée chaque fois que vous votez. Si vous validez le formulaire sans avoir voté, vous devriez voir le message d'erreur.

Utiliser des vues génériques : moins de code c'est mieux

Les vues detail() (du Tutorial 3) et results() sont ridiculement simples -- et, comme signalé précédemment, redondantes. La vue index() (également du Tutorial 3), qui affiche une liste de sondages, est semblable.

Ces vues constituent une situation banale dans le développement Web : prendre des données dans la base de données selon un paramètre passé dans l'URL, charger un template et renvoyer la page mise en forme. Parce que la situation est si banale, Django fournit un raccourci, appelé vues génériques.

Les vues génériques permettent de s'en affranchir au point que vous n'avez même pas besoin d'écrire du code Python pour écrire une application.

Convertissons notre application sondage pour utiliser le système des vues génériques, nous pourrons ainsi effacer une bonne part de notre propre code. Il n'y a que quelques étapes pour la conversion. Nous devrons :

  1. Convertir l'URLconf.
  2. Supprimer quelques vues précédentes, devenues inutiles.
  3. Régler la gestion des URL pour ces nouvelles vues.

Lisez la suite pour les détails.

Pourquoi ce va-et-vient dans le code ?

En règle générale, lors de l'écriture d'une application Django, vous évaluerez si les vues génériques sont une bonne solution pour votre problème, et vous les utiliserez dès le départ plutôt que d'avoir à restructurer le code à mi-chemin. Mais nous nous sommes intentionnellement focalisés sur l'écriture des vues « à la dure » jusqu'à présent, pour aborder les concepts du core.

On doit connaître le calcul avant d'utiliser une calculatrice.

D'abord, ouvrez l'URLconf polls/urls.py. Elle ressemble à ceci, conformèment au tuto :

from django.conf.urls import patterns, include, url

urlpatterns = patterns('polls.views',
url(r'^$', 'index'),
url(r'^(?P<poll_id>\d+)/$', 'detail'),
url(r'^(?P<poll_id>\d+)/results/$', 'results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)

Modifiez-le comme ceci :

from django.conf.urls import patterns, include, url
from django.views.generic import DetailView, ListView
from polls.models import Poll

urlpatterns = patterns('',
url(r'^$',
ListView.as_view(
queryset=Poll.objects.order_by('-pub_date')[:5],
context_object_name='latest_poll_list',
template_name='polls/index.html')),
url(r'^(?P\d+)/$',
DetailView.as_view(
model=Poll,
template_name='polls/detail.html')),
url(r'^(?P\d+)/results/$',
DetailView.as_view(
model=Poll,
template_name='polls/results.html'),
name='poll_results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
)

Ici, nous utilisons deux vues génériques : ListView et DetailView. Respectivement, ces deux vues permettent l'abstraction des concepts « afficher une liste d'objets » et « afficher une page détail pour un type d'objet en particulier ».

  • Chaque vue générique doit connaître sur quel modèle elle agit. On le lui indique en utilisant le paramètre model.
  • La vue générique DetailView s'attend à ce que la valeur de la clé primaire capturée depuis l'URL soit appelée "pk", alors on a modifié poll_id en pk pour les vues génériques.
  • Nous avons ajouté une nom, poll_results, à la vue résultats ce qui nous donne un moyen de se référer à son URL plus tard (voir la doc sur naming URL patterns pour d'autres infos). Nous utilisons aussi ici la fonction url() de django.conf.urls. C'est une bonne habitude d'utiliser url() lorsque vous fournissez un motif de nom comme celui-ci.

Par défaut, la vue générique DetailView utilise un template appelé <app name>/<model name>_detail.html. Dans notre cas, elle utilisera le template "polls/poll_detail.html". L'argument template_name est utilisé pour dire à Django d'utiliser un template spécifique au lieu du template par défaut autogénéré. Nous avons également spécifié template_name pour la vue liste results -- on s'assure ainsi que la vue résultat et la vue détail auront une apparence différente, même si en coulisse elles sont toutes deux des DetailView.

De même, la vue générique ListView utilise un template par défaut appelé <app name>/<model name>_list.html; nous utilisons template_name pour dire à ListView d'utiliser notre template "polls/index.html".

Dans les parties précédentes de ce tuto, les templates étaient fournis avec un contexte qui contenait les variables contexte poll et latest_poll_list. Pour DetailView la variable poll est founie automatiquement -- puisque nous utilisons un modèle Django (Poll), Django sait déterminer un nom approprié pour une variable contexte. Cependant, pour ListView, la variable contexte généée automatiquement est poll_list. Pour surcharger cela, on fournit l'option context_object_name, en spécifiant que nous voulons utiliser latest_poll_list à la place. D'une autre façon, vous pourriez modifier vos templates pour correspondre aux nouvelles variables contexte par défaut -- mais c'est nettement plus facile de dire à Django d'utiliser la variable que vous voulez.

Vous pouvez maintenant effacer les vues index(), detail() et results() de polls/views.py. On n'en a plus besoins -- elles ont été remplacées par les vues génériques.

La dernière choe à faire est de corriger la gestion des URL pour tenir compte de l'utilisation des vues génériques. Dans la vue vote précédente, nous aons utilisé la fonction reverse() pour éviter de coder nos URLs en dur. Maintenant que nous avons basculé sur les vues génériques, nous devons modifier l'appel reverse() pour pointer vers notre nouvelle vue générique. Nous ne pouvons plus utiliser la fonction vue -- les vues génériques peuvent (et sont) utilisées de nombreuses fois -- mais nous pouvons utiliser le nom fourni :

return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))

Lancez le serveur, et utilisez votre nouvelle application Soondage basée sur les vues génériques.

Pour plus de détails sur les vues génériques, consultez generic views documentation.

A venir

Ce tuto se termine ici pour l'instant. Les prochains épisodes porteront sur:

  • Traitement avancés des formulaires
  • Utiliser le framework RSS
  • Utiliser le cache framework
  • Utiliser le framework comments
  • Fonctionnalités admin avancées : les droits
  • Fonctionnalités admin avancées : Custom JavaScript

D'ici là, vous voudrez peut-être savoir where to go from here

30 août 2012

Tuto « Première appli Django », partie 3

Ecrire votre première application Django, partie 3

Ce tuto débute là où le précédent tuto s'achève (vous aurez noté la progression logique :-) NdT) (consulter le Tutorial 2). Nous continuons l'application Web Poll et pour ce tuto, nous nous focaliserons sur la création de l'interface publique (c'est à dire les pages Webs du site, celles que voient les internautes lambda) et donc : “views.” (rien à voir avec le module Views de Drupal. Je sais ce que je dis, j'en viens :-) ).

Philosophie

Dans une application Django, une vue est un type de page web qui fait généralement un boulot donné et dispose de son propre template (dorénavant, je dirai template et vous comprendrez mise en page ). Par exemple, dans un application de blog, vous pourriez avoir les vues suivantes :

  • Page d'accueil du blog – affiche les derniers billets.
  • Liste des billets – page de permaliens qui mènent chacun vers un billet.
  • Archives par année – affiche tous les mois d'une année donnée et leurs billets.
  • Archives par mois – affiche tous les jours avec les billets d'un mois donné.
  • Archives par jour – affiche tous les billets d'un jour donné.
  • Commentaires – gère la publication des commentaires d'un billet donné.

Dans notre application Poll, nous auront les vues suivantes :

  • Page “index” des sondages – affiche les quelques derniers sondages.
  • Page “détail” de sondage – affiche un sondage, sans résultats mais avec un formulaire pour voter.
  • Page “résultats” de sondages – affiche les résultats d'un sondage donné.
  • Action Voter – gère les votes d'un choix donné pour un sondage donné.

Dans Django, chaque vue est représentée par une simple fonction Python.

Concevez vos URLs

La première étape dans l'écriture des vues consiste à créer votre structure d'URLs. Cela se fait en créant un module Python, appelé URLconf. Les URLconfs permettent à Django d'associer une URL donnée avec un code Python donné. .

Lorsqu'un internaute fait une demande d'une page générée par Django, le système regarde le paramètre ROOT_URLCONF, qui contient une chaîne en syntaxe Python. Django charge ce module et regarde une variable-module, appelé urlpatterns, qui est une suite de tuples au format suivant :

(regular expression, Python callback function [, optional dictionary])

Django démarre à la première expression rationnelle et parcourt la liste, en comparant l'URL demandée avec chaque expression rationnelle, juqu'à ce qu'il en trouve une qui corresponde.

Quand il trouve une correspondance, Django appelle la fonction callback Python, avec un objet HttpRequest comme premier argument, l'une des valeurs capturée dans l'expression rationnelle comme argument mot-clé, et, en option, des arguments mot-clé arbitraires puisés dans le dictionnaire (un troisième élément, facultatif, du tuple).

Pour en savoir davantage sur les objets HttpRequest, consultez Request and response objects. Pour plus d'infos sur URLconfs, consultez URL dispatcher.

Lorsque vous avez exécuté django-admin.py startproject mysite au début du tuto 1, un URLconf a été créé par défaut dans mysite/urls.py. Le paramètre ROOT_URLCONF (dans settings.py) a également initialisé pour pointer sur ce fichier :

ROOT_URLCONF = 'mysite.urls'

Voyons un exemple. Modifiez mysite/urls.py pour qu'il ressemble à ceci :

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
url(r'^polls/$', 'polls.views.index'),
url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
url(r'^admin/', include(admin.site.urls)),
)

Voyons cela en détail. Quand quelqu'un demande une page de votre site web -- disons "/polls/23/", Django chargera ce module Python, parce que le paramètre ROOT_URLCONF pointe dessus. Il trouve la variable nommée urlpatterns et parcourt les expression rationnelles dans l'ordre. Quand il en trouve une qui correspond -- r'^polls/(?P<poll_id>\d+)/$' -- il charge la fonction detail() de polls/views.py. Au final, il appelle cette fonction detail() comme ceci :

detail(request=, poll_id='23')

La partie poll_id='23' vient de (?P<poll_id>\d+). Utiliser des parenthèses autour d'un motif « capture » le texte correspondant à ce motif et l'envoie comme argument à la fonction view; ?P<poll_id> définit le nom qui sera utilisé pour identifier le motif correspondant; et \d+ est une expression rationnelle pour la correspondance d'une suite de chiffres (un nombre).

Comme les motifs d'URLs sont des expression rationnelles, il n'y a pas vraiment de limite à ce que l'on peut faire avec. Et il n'est pas nécessaire non plus de les dénaturer avec des ajouts comme .php -- à moins que vous n'ayez l'esprit tordu. Si c'est le cas, vous pouvez faire quelque chose comme :

(r'^polls/latest\.php$', 'polls.views.index'),

Mais ne le faites pas. C'est dément ! Ça n'a pas de sens !

Sachez que les expressions rationnelles ne cherchent pas des paramètres GET et POST, ou le nom de domaine. Par exemple, dans une requête http://www.example.com/myapp/, URLconf cherchera myapp/. Dans une requête http://www.example.com/myapp/?page=3, URLconf cherchera myapp/.

Si vous avez vesoin d'aide sur les expressions rationnelles, consultez Wikipedia's entry et aussi la doc du module re. Également, le livre "Mastering Regular Expressions" dey Jeffrey Friedl, édité par O'Reilly, est sensationnel.

Une dernière remarque : ces expressions rationnelles sont compilées la première fois que le module URLconf est chargé. Elles sont super rapides.

Ecrire votre première vue

Bon, nous n'avons pas encore créé une seule vue -- nous n'avons que URLconf. Mais assurons-nous que Django suit le URLconf correctement.

Démarrez le serveur de développement de Django :

python manage.py runserver

Maintenant, allez sur "http://localhost:8000/polls/" sur votre domaine avec votre navigateur internet. Vous devriez avoir une chatoyante page d'erreur disant ceci :

ViewDoesNotExist at /polls/

Could not import polls.views.index. View does not exist in module polls.views.

Cette erreur s'est produite parce que vous n'avez pas écrit de fonction index() dans le module polls/views.py.

Essayez "/polls/23/", "/polls/23/results/" et "/polls/23/vote/". Le message d'erreur vous mentionne la vue que Django a essayé de charger (sans la trouver, puisque vous n'avez pas encore écrit de vues).

C'est le moment de le faire. Ouvrez le fichier polls/views.py et mettez-y ce code Python :

from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll index.")

C'est la plus simple des vues possibles. Avec votre navigateur, allez dans "/polls/" et vous devriez voir votre texte.

Ajoutons maintenant quelques vues. Ces vues sont légèrement différentes parce qu'elles prennent un argument (celui capturé par l'expression rationnelle dans URLconf) :

def detail(request, poll_id):
return HttpResponse("You're looking at poll %s." % poll_id)
def results(request, poll_id):
return HttpResponse("You're looking at the results of poll %s." % poll_id)
def vote(request, poll_id):
return HttpResponse("You're voting on poll %s." % poll_id)

Allez voir dans votre navigateur, à l'url "/polls/34/". La méthode detail() sera exécutée et affichera n'importe quelle ID que vous indiquerez dans l'URL. Essayez "/polls/34/results/" et aussi "/polls/34/vote/" -- cela affichera le texte de substitution pour les résultats et les pages de vote.

Ecrire des vues qui font vraiment quelque chose

Chaque vue ne fait qu'une ou deux choses : renvoyer une objet HttpResponse contenant le contenu de la page demandée, ou lever une exception comme Http404. Le reste vous incombe.

Votre vue peut lire des données de votre base de données, ou pas. Elle peut utiliser le système de template de Django -- ou un système Python tiers -- ou pas. Elle peut générer un fichier PDF, une sortie XML, créer un fichier ZIP à la volée, tout ce que vous voulez, en utilisant les bibliothèques Python qui vous chantent.

Tout ce que veut Django c'est HttpResponse. Ou une exception.

Puisque c'est plus pratique, nous utiliserons l'API base de données de Django, abordée dans le Tutorial 1. Voici la vue  index(), qui affiche les 5 dernières questions des sondages, séparés par des virgules, par ordre chronologique :

from polls.models import Poll
from django.http import HttpResponse

def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
output = ', '.join([p.question for p in latest_poll_list])
return HttpResponse(output)

Il y a un problème : la mise en page est codée en dur dans la vue. Si vous voulez changer son aspect, vous devrez éditer le code Python. Utilisons plutôt le système de mises en page de Django pour dissocier la mise en page du code Python :

from django.template import Context, loader
from polls.models import Poll
from django.http import HttpResponse

def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
t = loader.get_template('polls/index.html')
c = Context({
'latest_poll_list': latest_poll_list,
})
return HttpResponse(t.render(c))

Ce code charge un template appelé "polls/index.html" et lui passe un contexte. Le contexte est un dictionnaire associant (mappant) les variables de template aux objets Python.

Rechargez la page et vous obtiendrez une erreur :

TemplateDoesNotExist at /polls/
polls/index.html

Ah. Il n'y a pas encore de mise en page (de template). Tout d'abord, créez un dossier sur votre disque, au contenu duquel Django pourra accèder (Django tourne en tant qu'utilisateur qui fait tourner le serveur). Mais ne le mettez pas dans le dossier racine, vous ne voudriez pas rendre ce dossier public (pour des raisons de sécurité). Ensuite, éditez le TEMPLATE_DIRS de votre settings.py pour dire à Django où il peut trouver les templates -- tout comme vous l'avez fait dans la section « Personnaliser le look and feel de la page admin » du tuto 2.

Ensuite, créez un dossier polls dans le dossier de vos templates. Et créez à l'intérieur un fichier appelé index.html. Remarquez que le code loader.get_template('polls/index.html') pointe vers "[template_directory]/polls/index.html" sur le disque.

Mettez le code suivant dans le template :

{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

Chargez la page dans votre navigateur Internet, et vous devriez voir une liste à puces contenant le sondage « What's up » du tuto 1. Le lien pointe vers la page détail du sondage.

Un raccourci : render_to_response()

Charger une mise en page, lui fournir un contexte et renvoyer un objet HttpResponse avec le résultat est une tâche très fréquente. Django fournit un raccourci. Voici la vue index() complète, réécrite :

from django.shortcuts import render_to_response
from polls.models import Poll

def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})

Notez qu'une fois que nous avons fait ça dans toutes ces views, nous n'avons plus besoin d'importer loader, Context et HttpResponse.

La fonction render_to_response() prend un nom de template comme premier argument et, en option, un dictionaire comme deuxième argument. Elle renvoie un objet HttpResponse du tempalte, mis en page avec le contexte donné.

Soulever une erreur 404

occupons-nous maintenant de la vue détail du sondage -- la page qui affiche la question d'un sondage donné. Voici la vue :

from django.http import Http404
# ...
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p})

Voici le nouveau concept : la vue lève une erreur Http404 si le sondage avec l'ID demandé n'existe pas.

Nous verrons plus tard ce que vous pouvez mettre dans ce template polls/detail.html, mais si vous voulez avoir le précédent exemple opérationnel  :

{{ poll }}

le fera.

Un raccourci : get_object_or_404()

Comme il est plutôt courant d'utiliser get() et de lever une erreur Http404 si un objet n'existe pas, Django fournit un raccourci. Voici la vue detail() réécrite :

from django.shortcuts import render_to_response, get_object_or_404
# ...
def detail(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/detail.html', {'poll': p})

La fonction get_object_or_404() prend un modèle Django comme premier argument et un nombre arbitraire de clés comme arguments, qu'elle passe à la fonction get() du module. Elle lève une erreur Http404 si l'objet n'existe pas.

Philosophie

Pourquoi utiliser une fonction get_object_or_404() auxiliaire au lieu de capturer automatiquement les erreurs ObjectDoesNotExist à un plus haut niveau, ou laisser l'API Model lever Http404 au lieu de ObjectDoesNotExist ?

Parce que cela couplerait le modèle Layer au modèle View. Et l'un des buts de Django est de garder un bas niveau de "couplage".

Il y a aussi une fonction get_list_or_404(), qui travaille comme get_object_or_404() -- sauf qu'elle utilise filter() au lieu de get(). Elle lève Http404 si la liste est vide.

Écrire une vue 404 (page non trouvée)

Lorsque vous levez une erreur Http404 depuis une vue, Django chargera une vue spéciale dédiée à la gestion des erreurs 404. Il la trouve en cherchant la variable handler404 dans votre URLconf racine (et seulement dans votre URLconf racine; mettre handler404 ailleurs sera sans effet), qui est une chaine Python à syntaxe point -- le même format que l'URLconf callback normal utilise. Une vue 404 n'a rien de spécial : c'est simplement une vue normale.

Vous n'avez en principe pas à vous occuper d'écrire des vues 404. ou normally won't have to bother with writing 404 views. Si vous ne paramètrez pas handler404, la vue par défaut django.views.defaults.page_not_found() sera utilisée. Dans ce cas, vous devez quand même créer un template nommé 404.html dans la racine de votre dossier des templates. La vue 404 par défaut utilisera ce template pour toutes les erreurs 404. Si DEBUG est paramétré à False (dans votre module des paramètrages) et si vous ne créez pas de fichier 404.html une erreur Http500 sera levée à la place. Donc n'oubliez pas de créer un fichier nommé 404.html.

Quelques choses à savoir aussi au sujet de vues 404 :

  • Si DEBUG est paramétré à True (dans votre module de paramétrages) votre vue 404 ne sera jamais utilisée (et par conséquent, votre template 404.html ne le sera pas non plus), parce que le traceback sera affiché à la place.
  • LA vue 404 sera également appelé si Django ne trouve pas de correspondance après avoir examiné chaque expression rationnelle dans URLconf.

Ecrire une vue 500 (erreur serveur)

De même, votre URLconf racine peut définir un handler500, qui pointe sur une vue à appeller en cas d'erreurs serveur. Les erreurs serveur se produisent lorsque vous avez des erreurs d'exécution (runtime errors) dans le code d'une vue.

Utiliser le système de templates

Revenons à la vue detail() de notre application de sondage. Etant donné la variable contexte poll, voici à quoi ressemblera le template "polls/detail.html" :

{{ poll.question }}

{% for choice in poll.choice_set.all %}
{{ choice.choice }}
{% endfor %}

Le système de templates utilise une syntaxe ≤em>dot-lookup pour accèder aux attributs des variables. Dans cet exemple {{ poll.question }}, Django cherche d'abord dans le dictionnaire de l'objet poll. En cas d'échec, il cherche dans les attributs -- ce qui fonctionne dans notre exemple. Si la recherche dans les attributs avait échoué, il aurait cherché dans l'index de la liste.

L'appel des méthodes a lieu dans la boucle {% for %} : poll.choice_set.all est interprété en tant que code Python de poll.choice_set.all(), qui renvoie un itérable d'objets Choice utilisables dans la balise {% for %}.

Consultez le template guide pour d'autres infos sur les templates.

Simplifier les URLconfs

Prenez un peu de temps pour expérimenter le système de vues et de templates. Lorsque vous avez édité URLconf, vous avez peut-être remarqué quelques redondances :

urlpatterns = patterns('',
url(r'^polls/$', 'polls.views.index'),
url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
)

A savoir, polls.views est dans tous les callback.

Comme c'est une situation courante, le framework URLconf fournit des raccourcis pour les prefixes souvent utilisés. Vous pouvez exclure les préfixes communs et les ajouter comme premier argument de patterns(), comme ceci :

urlpatterns = patterns('polls.views',
url(r'^polls/$', 'index'),
url(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
)

Cette fonctionnalité est identique à la précédente. Elle est just un peu mieux ordonnée.

Comme vous ne voudrez sans doute pas que le préfixe d'une application s'applique à chaque callback de votre URLconf, vous pouvez concaténer plusieurs patterns(). Votre mysite/urls.py ressemblera alors à ceci :

from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('polls.views',
url(r'^polls/$', 'index'),
url(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
)
urlpatterns += patterns('',
url(r'^admin/', include(admin.site.urls)),
)

Découpler les URLconfs

Tant que nous y sommes, prenons le temps de découpler les URls de notre application sondage du paramètrage de notre projet Django. Les applications Django sont faites pour être « pluggées », ce qui veut dire que chaque application doit pouvoir être transférée sur une autre installation Django avec un minimum d'adaptations.

A ce stade, notre application de sondage est plutôt bien découplée, grâce à la structure de dossiers que python manage.py startapp a créée, mais une partie reste couplée aux paramètres Django : URLconf.

Nous avons modifié les URLs dans mysite/urls.py, mais la conception des URl d'une application est propre à cette application, pas à l'insallation de Django -- alors déplaçons les URLs dans le dossier de l'application.

Copiez le fichier mysite/urls.py dans polls/urls.py. Puis modifiez mysite/urls.py pour ôter les URLs propres à l'application de sondage et insérez un include(), ce qui vous donne :

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
url(r'^polls/', include('polls.urls')),
url(r'^admin/', include(admin.site.urls)),
)

include() référence simplement un autre URLconf. Remarquez que l'expression rationnelle n'a pas de $ (caractère symbolisant une de fin de ligne) mais a un slash de fin. Lorsque Django rencontre include(), il coupe la partie de l'URL correspondante jusque-là et envoie la chaîne restante à l'URLconf inclu pour la suite du traitement.

Voici ce qui se passe dans ce cas si un internaute va sur "/polls/34/" :

  • Django trouvera la correspondance à '^polls/'
  • Ensuite, Django supprimera le texte correspondan ("polls/") et enverra le rest du texte -- "34/" -- à l'URLconf de 'polls.urls' pour la suite du traitement.

Maintenant que nous avons découplé cela, nous devons découpler l'URLconf polls.urlsen supprimant les "polls/" qui sont en tête de chaque ligne, et en enlevant les lignes qui enregistrent la partie admin du site. Votre fichier polls/urls.py devrait maintenant ressembler à ça :

from django.conf.urls import patterns, include, url

urlpatterns = patterns('polls.views',
url(r'^$', 'index'),
url(r'^(?P<poll_id>\d+)/$', 'detail'),
url(r'^(?P<poll_id>\d+)/results/$', 'results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)

L'idée derrière include() le découplage d'URLconf est de faciliter le plug-and-play des URL. Maintenant que les sondages ont leur propre URLconf, ils peuvent être placés dans "/polls/", ou dans "/fun_polls/", ou dans "/content/polls/", ou ailleurs dans votre path racine, et l'application fonctionnera toujours.

Toute l'application Poll utilise son chemin relatif, pas son chemin absolu.

Lorsque vous serez à l'aise avec l'écriture des vues, vous pourrez passer à part 4 of this tutorial pour apprendre les traitements des formulaires simples et les vues génériques.

29 août 2012

Tuto « Première appli Django », partie 2

Écrire votre première application Django, partie 2 

Ce tutoriel débute là où le Tutorial 1 s'achève. Nous continuons l'écriture de l'application Web de sondage et nous nous focaliserons sur la génération automatique de la partie administration d'un site par Django.

Philosophie

La création de la partie administrative d'un site pour que votre équipe, ou vos clients, puissent ajouter, modifier et supprimer du contenu n'est pas la partie la plus folichonne à réaliser et ne demande pas beaucoup de créativité. Pour cette raison, Django automatise entièrement la création de l'interface d'administration pour les modèles.

Django a été écrit dans l'environnement d'une salle de rédaction, avec une séparation très nette entre la publication des contenus et le site public. Les gestionnaires de sites utilisent le système pour ajouter de nouveaux articles, événements, résultats sportifs, etc, et ce contenu est affiché sur le site public. Django résout la question de la création d'une interface d'administration unifiée pour que les gestionnaires de site éditent le contenu.

La partie administration n'est pas destinée à être utilisée par lesq internautes. Elle est destinée aux administrateurs du site.

Activer la partie administration

La partie administration d'un site Django n'est pas activée par défaut. Pour l'activer, faites les trois choses suivantes :

  • Décommentez "django.contrib.admin" dans le paramètre INSTALLED_APPS .

  • Exécutez python manage.py syncdb. Puisque vous avez ajouté une nouvelle application dans INSTALLED_APPS, la base de données doit être actualisée.

  • Editez votre fichier mysite/urls.py et décommentez les lignes qui référencent la partie admin – il y a trois lignes à décommenter en tout. Ce fichier est un URLconf; nous approfondirons URLconfs dans le prochain tuto. Pour l'instant, tout ce que vous avez besoin de savoir c'est qu'il définit les racines des URL de vos applications. Au final, vous devriez avoir un fichier urls.py qui ressemble à ceci :

    from django.conf.urls import patterns, include, url

    # Decommentez les deux prochaines lignes pour activer admin:
    from django.contrib import admin
    admin.autodiscover()

    urlpatterns = patterns('',
    # Exemples:
    # url(r'^$', '{{ project_name }}.views.home', name='home'),
    # url(r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),

    # Décommentez la ligne admin/doc line ci-dessous pour activer la documentation de l'admin:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Décommentez la ligne suivante pour activer l'admin :
    url(r'^admin/', include(admin.site.urls)),
    )

    (Les lignes en gras sont celles qui doivent être décommentées.)

Démarrer le serveur de développement

Démarrez le serveur de développement et explorez la partie admin du site.

Le premier tuto vous a dit que le démarrage du serveur de développement se fait comme ceci :

python manage.py runserver

Maintenant, ouvrez un navigateur internet et allez sur "/admin/" de vote domaine local -- par exemple, http://127.0.0.1:8000/admin/. Vous devriez voir le login de l'interface d'admin :

Django admin login screen

Ça ne correspond pas à ce que vous avez ?

Si à ce stade vous avez une page d'erreur à la place du login de la partie admin et qu'elle vous dit quelque chose comme ceci :

ImportError at /admin/
cannot import name patterns
...

c'est que vous utilisez probablement une version de Django qui ne correspond pas à ce tutoriel. Vous avez le choix entre basculer vers l'ancien tutoriel ou vers la nouvelle version de Django.

Entrer dans le site d'administration

Maintenant, loggez-vous (vous avez créé un compte super-utilisateur dans la première partie de ce tutoriel, vous vous en souvenez ? Si vous ne l'avez pas fait ou si vous avez oublié le mot de passe, vous pouvez en create another one.) Vous devriez obtenir la page d'index de la partie admin du site Django :

Django admin index page

Vous devriez voir quelques types de contenus éditables, y compris les groupes, les utilisateurs et les sites. Ce sont des fonctionnalités du core que Django fournit par défaut.

Rendre le sondage modifiable dans la partie admin

Mais où est donc notre application sondage ? Elle n'est pas affichée sur la page d'index.

Une seule chose à faire : dire à admin que l'objet Poll a une interface d'administration. Pour cela, créer un fichier appelé docutils literal">admin.py dans le dossier de polls et l'éditer pour qu'il ressemble à cela :

from polls.models import Poll
from django.contrib import admin

admin.site.register(Poll)

Vous devrez redémarrer le serveur de développement pour voir les changements. Normalement, le serveur recharge automatiquement le code chaque fois que vous modifiez un fichier, mais la création d'un nouveau fichier ne déclenche pas le rechargement automatique.

Explorer les fonctionnalités libres de la partie administration

Maintenant que nous avons enregistré Poll, Django sait qu'il doit être affiché dans l'index de la partie administration :

index de page admin Django, avec les sondages affichés

Cliquez sur "Polls." Vous êtes maintenant dans la page "change list" des sondages. Cette page affiche tous les sondages de la base de données et vous permet d'en choisir un pour le modifier. Il y a le sondage "What's up?" créé dans le premier tuto :

Page listing pour les modifications de Poll

Cliquez sur le sondage "What's up?" pour le modifier :

Edition du formulaire pour l'objet poll

Quelques remarques opportunes :

  • Le formulaire est automatiquement généré à partir du modèle Poll.
  • Les diférents types de champs (DateTimeField, CharField) correspondent à leur widget HTML pour leur saisie. Chaque type de champs sait comment s'afficher dans la partie admin de Django.
  • Chaque DateTimeField dispose de raccourcis JavaScript . Les dates ont un raccourci "Today" et un calendrier pop-up, et les heures ont un raccourci "Now" et un popup adapté qui liste les heures les plus courantes.

La fin de la page vous donne quelques options :

  • Save -- Sauvegarde les modifications et retourne à la liste de cet objet.
  • Save and continue editing -- Sauvegarde les modifications et recharge la page d'admin de cet objet.
  • Save and add another -- Sauvegarde les modifications et charge un nouveau formulaire vierge pour l'objet.
  • Delete -- Affiche une page de confirmation pour la suppression.

Si la valeur de "Date published" ne correspond pas à l'heure de création du sondage, c'est que vous n'avez probablement pas bien paramétré la valeur de TIME_ZONE. Modifiez-le, rechargez la page et vérifiez que la bonne valeur est affichée..

Changez "Date published" en cliquant sur les racccourcis "Today" et "Now". Puis cliquez sur "Save and continue editing." Cliquez ensuite sur "History" en haut à droite. Vous verrez un listing de toutes les modifications faites sur cet objet via l'admin Django, avec le timbre à date et le nom d'utilisateur qui a effectué la modif :

Page Hisorique de l'objet Poll

Personnaliser le formulaire d'administration

Prenez quelques instant pour vous émerveiller devant tout ce code que vous n'avez pas eu à écrire. En enregistrant le modèle Poll avec admin.site.register(Poll), Django a été capable de construire un affichage par défaut. Vous voudrez sans doute personnaliser le formulaire d'administration. Vous le ferez en communiquant vos options à Django, lors de l'enregistrement de l'objet.

Voyons comment ça marche en réorganisant les champs du formulaire d'édition. Remplacez la ligne admin.site.register(Poll) avec :

class PollAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question']

admin.site.register(Poll, PollAdmin)

Vous suivrez ce modèle -- créer un modèle admin objet, le passer en deuxième argument à admin.site.register() -- chaque fois que vous devrez modifier les options d'admin pour un objet.

La moodif précédente place le champ "Publication date" avant le champ "Question" :

Les champs ont été réorganisés

Ce n'est pas très impressionnant avec suelement deux champs, mais pour les formulaires d'administration qui contiennent des douzaines de champs, choisir un ordre intuitif est un avantage ergonomique non negligeable.

Et à propos des formulaires comportant des douzaines de champs, vous voudrez peut-être diviser le formulaire en plusieurs zones (fieldsets) :

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Poll, PollAdmin)

Le premier élément e chaque tuple dans fieldsets est le titre du fieldset. Voici à quoi ressemble le formulaire maintenant :

Le formulaire a désormais des fieldsets

Vous pouvez attribuer des classes HTML à chaque fieldset de façon arbitraire. Django fournit une classe "collapse" qui affiche un fieldset donné initialement replié. C'est utile lorsque vous avez un long formulaire qui contient des champs peu utilisés :

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]

Le fieldset est initialement replié

Personnaliser l'administration des listes de modifications

Maintenant que la page d'administration de Poll est ok, occupons-nous de lodifier la page "change list" -- celle qui affiche tous les sondages du système.

Voilà à quoi elle ressemble pour l'instant :

Page pour les modifications de Poll

Par défaut, Django affiche le str() de chaque objet. Mais parfois, ce serait plus pratique si on pouvait afficher des champs individuels. pour cela, il faut utiliser l'option d'administration list_display, qui est un tuple de noms de champs à afficher, en colonnes, sur la page des modifs de l'objet :

class PollAdmin(admin.ModelAdmin):
# ...
list_display = ('question', 'pub_date')

Pour la bonne bouche, ajoutons aussi la méthode personnalisée was_published_recently vue dans le premier tuto :

class PollAdmin(admin.ModelAdmin):
# ...
list_display = ('question', 'pub_date', 'was_published_recently')

Maintenant, la page d'administration de modifs pour poll ressemble à ceci :

Page pour les modifications de Poll, actualisée

Vous pouvez cliquer sur les entêtes de colonne pour trier les valeurs -- sauf pour was_published_recently, car le tri des résultats fournis par une méthode arbitraire n'est pas supporté. Notez également que l'entête de colonne de was_published_recently est, par defaut, le nom de la méthode (avec les underscores remplacés par des espaces), et que chaque ligne contient la représentation en string de la sortie (oui, j'ai traduit cette ligne en revenant de la plage, où j'avais sorti mon dernier string. NdT).

Vous pouvez améliorez ça en donnant quelques attributs à cette méthode (dans models.py), comme ceci :

class Poll(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'

Modifiez encore votre fichier admin.py et ajoutez cette amélioration à la page Liste des modifications pour Poll : Filters. Ajoutez la ligne suivante à PollAdmin :

list_filter = ['pub_date']

Cela ajoute une barre latérale (sidebar en VO. NdT) "Filter" qui permet aux utilisateurs de filtrer la Liste des modifications sur le champs pub_date :

Page pour les modifications de Poll, actualisée

Le type de filtre affiché dépend du type dechamp sur lequel porte le filtre. Comme pub_date est un DateTimeField, Django sait fournir les options de filtre appropriées : "Any date," "Today," "Past 7 days," "This month," "This year."

Cela a meilleure allure. Ajoutons des possibilités de recherches :

search_fields = ['question']

Cela ajoute une zone de recherche en haut de la page. Lorsqu'un utilisateur saisira des mots à rechercher, Django les cherchera dans le champ question. Vous pouvez utiliser autant de champs que vous le souhaitez -- mais comme Django utilise la clause LIKE dans la requête, soyez raisonnable, pour ne pas contrarier vote base de données.

Enfin, comme l'objet Poll comporte des dates, ça serait bien pratique de pouvoir classer par date. Ajoutez cette ligne :

date_hierarchy = 'pub_date'

Cela ajoute une navigation hiérarchique, par date, en haut de chaque page Liste de modifications. Au premier niveau, on affiche toutes les années disponibles. Puis on descend aux mois et, en dernier lieu, aux jours.

C'est le moment opportun pour dire que les Listes de modifications vous donnent une totale liberté pour la pagination. Par défaut, 100 items par page sont affichés. La pagination, les zones de recherche, les filtres, les hierarchies pour les dates et le tri via les entêtes de colonne, tout marche ensemble, car c'est ainsi que cela doit marcher.

Personnaliser le look and feel de la page d'administration

Franchement, mettre "Django administration" en haut de chaque page est ridicule. En fait, c'est juste un texte de substitution (placeholder text en VO. NdT).

C'est facile à changer. En utilisant toutefois le système de mises en page de Django. Les pages d'administration de Django sont générées par Django lui-même, et ses interfaces utilisent donc le système de mises en page de Django.

Ouvrez votre fichier de paramètres (mysite/settings.py) et regardez le paramètre TEMPLATE_DIRS. TEMPLATE_DIRS est un tuple des dossiers à vérifier lors du chargement des templates Django. C'est un path de recherche.

Par défaut, TEMPLATE_DIRS est vide. Alors ajoutons-lui une ligne, pour dire à Django où se trouvent nos templates :

TEMPLATE_DIRS = (
'/home/my_username/mytemplates', # Change this to your own directory.
)

Maintenant, copiez le template admin/base_site.html depuis le répertoire par défaut des templates admin de Django, situé dans le code-source de Django (django/contrib/admin/templates) vers un sous-dossier admin ne n'importe quel dossier indiqué dans TEMPLATE_DIRS. Par exemple, si votre TEMPLATE_DIRS contient '/home/my_username/mytemplates', comme ci-dessus, copiez django/contrib/admin/templates/admin/base_site.html vers tt class="docutils literal">/home/my_username/mytemplates/admin/base_site.html. N'oubliez pas ce sous-dossier admin.

Où se trouvent les fichiers source de Django ?

Si vous avez du mal à localiser les fichiers source de Django dans votre système, exécutez la commande suivante :

python -c "
import sys
sys.path = sys.path[1:]
import django
print(django.__path__)"

Ensuite, modifiez le fichier et remplacez le texte générique de Django par votre propre texte.

Le fichier template contient un paquet de texte comme {% block branding %} et {{ title }}. Les balises {% et {{ font partie du langage de template de Django. Quand Django mouline admin/base_site.html, ce langage de template est utilisé pour produire la page HTML finale. Ne vous inquiètez pas si vous ne comprenez pas les template maintenant -- nous aborderons cet aspect de Django dans le tuto 3.

Sachez que tout template par défaut de pages d'admin de Django peut être surchargé. Pour surcharger un template, faites-là même chose que pour base_site.html -- copiez-le du dossier par défaut vers votre dossier personnalisé, et faites les modifs.

Les lecteurs perspicaces demanderont : « mais si TEMPLATE_DIRS était vide par défaut, comment Django a-t-il trouvé les templates d'admin par défaut ? » La réponse est que Django, par défaut, cherche automatiquement un sous-dossier templates/ dans chaque package d'applications, pour l'utiliser en solution de repli. Consultez template loader documentation pour toute la doc.

Personnalisez la page index d'Admin

De la même façon, vous voudrez peut-être personnaliser le look and feel de la page index de l'administration.

Elle affiche par défaut toutes les applications INSTALLED_APPS qui ont été enregistrées avec l'application admin, dans l'ordre alphabétique. Vous voudrez peut-être apporter de substantielles modifications à la mise en page. Après tout, la page d'index est sans doute la page la plus importante de l'administration et elle devrait être simple à utiliser.

Le template à personnaliser est admin/index.html. (faites la même chose qu'avec admin/base_site.html dans la précédente section. -- copiez-le depuis le dossier par défaut vers votre dossier de templates personnalisés). Editez le fichier et vous verrez qu'il utilise une variable de tempalte appelée app_list. Cette variable contient chaque application Django installée. Au lieu de l'utiliser, vous pouvez coder en dur les liens vers les pages d'admin d'objets en particulier, de la façon qui vous semble la plus appropriée. Une fois encore, ne vous inquiétez pas si vous ne comprenez pas le langage de template -- nous l'approfondirons dans le tuto 3.

Quand vous serez à l'aise avec la partie administration du site, lisez part 3 of this tutorial pour commencer à travailler sur les vues publiques des sondages.

28 août 2012

Tuto « Première appli Django », partie 1

Écrire votre première application Django, première partie

Apprenons par l'exemple.

Dans ce tutoriel, vous apprendrez à créer une application sondage basique.

Elle comportera deux parties :

  • Une partie publique dans laquelle les utilisateurs verront les sondages et pourront voter.
  • Une partie administration dans laquelle vous ajouterez, modifierez et supprimerez des sondages.

Nous supposerons que Django est déjà installé. Vous saurez si Django est installé en lançant l'interpréteur interactif Python et en tapant import django. Si cette commande ne retourne pas d'erreur c'est que Django est installé.

Où trouver de l'aide :

Si vous rencontrez des problèmes avec ce tutorial, vous pouvez poster un message dans django-users ou aller sur #django on irc.freenode.net pour discuter avec d'autres utilisateurs Django susceptibles de vous aider.

Créer un projet

Si vous utilisez Django pour la première fois, vous devrez effectuer un premier paramétrage. C'est à dire, vous devrez auto-générer le code qui fonde un projet Django – un ensemble de paramètres pour une instance de Django, comprenant notamment, le paramétrage de la base de données, des options propres à Django et des paramètres propres à l'application.

Depuis la ligne de commande, cd dans un dossier dans lequel vous enregistrerez votre code, puis exécutez la commande suivante :

django-admin.py startproject mysite

Cela créera un dossier mysite dans votre dossier courant.

Le nom du script peut différer dans les paquetages des distributions

Si vous avez installé Django en utilisant le gestionnaire de paquets d'une distribution Linux (par exemple apt-get or yum) django-admin.py peut avoir été renommé en django-admin. Vous poursuivrez dans cette documentation en omettant .py dans chaque commande.

Droits Mac OS X

Si vous utilisez Mac OS X, vous aurez peut-être le message "permission denied" lorsque vous essaierez de lancer django-admin.py startproject. La raison est que, sur les systèmes de type Unix comme l'est OS X, un fichier doit être marqué comme "exécutable" avant de pouvoir être exécuté en tant que programme. Pour ce faire, ouvrez Terminal.app et naviguez jusqu'au dossier où se trouve django-admin.py (en utilisant la commande cd ), puis exécutez la commande sudo chmod +x django-admin.py.

Note

Vous ne devrez pas utiliser des noms de composants Python ou Django pour nommer vos projets. En particulier, n'utilisez pas des noms comme django (qui rentrera en conflit avec Django lui-même) ou test (qui rentrera en conflit avec des composants intégrés de Python).

django-admin.py devrait se trouver sur le chemin système si vous avez installé Django via python setup.py. S'il ne se trouve pas dans votre path vous pouvez le trouver dans site-packages/django/bin, où site-packages est un dossier dans votre installation Python. Pensez à créer un lien symbolique vers django-admin.py depuis quelque part dans votre path, comme /usr/local/bin.

Où se trouve le code ?

Si vous êtes un habitué de PHP, vous avez sans doute l'habitude de placer votre code dans le dossier racine du document sur votre serveur Web (dans un dossier comme /var/www). Avec Django, vous ne procédez pas ainsi. Mettre quoi que ce soit du code Python dans le dossier racine du document sur le serveur Web est une mauvaise idée, parce que les visiteurs de votre site auront la possibilité de voir votre code. C'est mauvais pour la sécurité.

Mettez votre code dans un dossier à l'extérieur du dossier racine de votre document, comme /home/mycode.

Regardons ce que startproject a créé :

mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py

Ça ne ressemble pas à ce que vous avez ?

Le squelette de projet par défaut a récemment changé. Si vous voyez un layout "plat" (sans dossier mysite/ imbriqué), c'est que vous êtes probablement en train d'utiliser une version de Django qui ne correspond pas à ce tutoriel. Vous avez donc le choix entre lire un tutoriel plus ancien, ou basculer vers une version de Dango plus récente.

Ces fichiers sont :

  • Le dossier "extérieur" mysite/ est juste un container pour votre projet. Pour Django son nom importe peu; vous pouvez le renommer comme vous le voulez.
  • manage.py: un utilitaire en ligne de commande qui vous permet d'interagir de plusieurs façons avec le projet Django. Vous lirez tous les détails sur manage.py dans django-admin.py et manage.py.
  • Le dossier intérieur mysite/ est le vrai paquet Python de votre projet. Son nom est le nom du paquet Python que vous utiliserez pour importer quoi que ce soit dedans (par exemple import mysite.settings).
  • mysite/__init__.py: un fichier vide qui dit à Python quer ce dossier doit être considéré comme un paquet Python. (si vous êtes débutant en Python, lire more about packages dans la documentation officielle Python.)
  • mysite/settings.py: Paramètrages et configuration pour ce projet Django. Django settings vous dira tout sur le fonctionnement des paramétrages.
  • mysite/urls.py: les déclarations d'URL pour ce projet Django; une "table des matières" de votre site Django. Vous en saurez plus sur les URLs dans URL dispatcher.
  • mysite/wsgi.py: un point d'entrée pour les serveurs web compatibles WSGI pour servir votre projet. Voir How to deploy with WSGI pour plus d'infos.

Le serveur de développement

Vérifions s'il fonctionne. Placez-vous dans le dossier mysite externe, si vous n'y êtes pas déjà, et lancez la commande python manage.py runserver. Vous verrez l'affichage suivant sur la ligne de commande :

Validating models...
0 errors found.

Django version 1.4, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Vous venez de démarrer le serveur de développement de Django, un serveur Web léger, entièrement écrit en Python. Nous l'avons ajouté à Django pour que vous puissiez développer vos œuvres rapidement, sans avoir à vous farcir la configuration d'un serveur de production -- comme Apache -- jusqu'à ce que vous soyez prêts pour la production.

C'est le bon moment pour une bonne remarque : N'UTILISEZ PAS ce serveur pour quoi que ce soit qui ressemblerait à un environnement de production. Il n'est destiné qu'à des fins de développement. (Notre boulot c'est de faire des frameworks Web, pas de faire des serveurs Web).

Maintenant que le serveur fonctionne, allez sur la page http://127.0.0.1:8000/ avec votre navigateur web. Vous verrez une page de bienvenue Django, dans un flatteur bleu clair aux tons pastel. Ça marche !

Changer le port

Par défaut la commande runserver démarre le serveur de développement sur le port IP interne 8000.

Si vous voulez modifier le port du serveur, passez-le en argument dans la ligne de commande. Par exemple, cette commande démarrera le serveur sur le port 8080 :

python manage.py runserver 8080

Si vous voulez modifier l'IP du serveur, passez-là avec le port. Ainsi, pour écouter toutes les IP publiques (utile si vous voulez vous la jouer avec votre travail sur d'autres ordinateurs), utilisez :

python manage.py runserver 0.0.0.0:8000

Les docs complètes pour le serveur de développement peuvent être trouvées sur runserver reference.

Paramétrage de la base de données

Editer maintenant mysite/settings.py. C'est un module Python tout ce qu'il y a de plus normal, avec des variables module-level représentant les paramètres Django. Modifiez les clés suivantes de l'item DATABASES 'default' pour leur donner vos paramètres de connexion.

  • ENGINE -- Soit 'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql', 'django.db.backends.sqlite3' ou 'django.db.backends.oracle'. D'autres backends sont également disponibles.

  • NAME -- Le nom de votre base de données. Si vous utilisez SQLite, la base de données sera un fichier sur votre ordinateur; dans ce cas , NAME devra être le chemin absolu complet du fichier, y compris avec le nom de fichier. Si le fichier n'existe pas, il sera automatiquement crée lorsque vous synchroniserez la base de données pour la première fois (voir ci-dessous)

    Lorsque vous spécifiez le path, utilisez toujours des slashs, même sur Windows (par exemple : C:/homes/user/mysite/sqlite3.db).

  • USER -- Votre nom d'utilisateur dans la base de données (inutilisé avec SQLite).

  • PASSWORD -- votre mot de passe pour la base de données (inutilisé avec SQLite).

  • HOST -- L'hôte de votre base de données. Laissez la chaîne en blanc si votre serveur de base de données se trouve sur la même machine physique (inutilisé avec SQLite).

Si vous débutez avec les bases de données, nous vous recommandons d'utiliser simplement SQLite en paramétrant ENGINE à 'django.db.backends.sqlite3' et NAME avec l'endroit où vous voulez enregistrer la base de données. SQLite fait partie de Python 2.5 et ultérieurs, vous n'aurez donc pas à installer quoi que ce soit d'autre pour utiliser votre base de données.

Note

Si vous utilisez PostgreSQL ou MySQL, soyez sûr d'avoir déjà créé la base de données. Faites-le en tapant "CREATE DATABASE database_name;" avec l'invite de commande interactive de votre base de données.

Si vous utilisez SQLite, vous n'avez pas besoin de créer quoi que ce soit d'avance - le fichier base de données sera créé automatiquement au moment opportun.

Lors de l'édition de settings.py, paramétrez TIME_ZONE sur votre fuseau horaire. La valeur par défaut est Central time zone aux U.S.A. (Chicago).

Regardez aussi le paramètre INSTALLED_APPS vers la fin du fichier. Il recense les noms de toutes les applications Django qui sont activées dans cette instance. les applications peuvent être utilisées dans de multiples projets, et vous pouvez les rassembler et les distribuer pour d'autres utilisateurs dans leurs projets.

Par défaut, INSTALLED_APPS contient les applications suivantes, qui sont toutes fournies avec Django :

Ces applications sont fournies par défaut comme commodité pour les cas courants.

Chacune de ces applications utilise au moins une table de base de données et nous devons créer les tables dans la base de données avant de pouvoir les utiliser. Pour cela, exécutez la commande suivante :

python manage.py syncdb

La commande syncdb examine le paramètre INSTALLED_APPS et crée toutes les tables requises dans la base de données conformément aux paramètres de votre fichier settings.py. Vous verrez un message pour chaque table créée et vous aurez une invite vous demandant si vous voulez créer un compte super utilisateur pour le système d'authentification. Allez-y et faites-le.

Si cela vous branche, lancez la ligne de commande de votre base de données et tapez \dt (PostgreSQL), SHOW TABLES; (MySQL), ou .schema (SQLite) pour afficher les tables que Django a créées.

Pour les minimalistes

Comme nous l'avons dit précédemment, les applications par défaut sont livrées pour les cas habituels, mais tout ne le monde n'en a pas besoin. Si certaines vous semblent inutiles, n'hésitez pas à dé-commenter ou effacer les lignes correspondantes de INSTALLED_APPS avant de lancer syncdb. La commande syncdb ne créera que les tables des applications dans INSTALLED_APPS.

Créer les modèles 

Maintenant que votre environnement -- un "projet" -- est mis en place, vous pouvez commencer le travail.

Chaque application que vous écrivez dans Django consiste en un paquet Python, quelque part sur votre Python path, qui respecte une convention donnée. Django est fourni avec un utilitaire qui génère automatiquement la structure de base des dossiers d'une application, vous pouvez donc vous focaliser sur l'écriture du code plutôt que sur la création des dossiers.

Projets vs. apps

Quelle différence entre un projet et une app ? Une app est une application Web qui fait quelque chose -- par exemple, un système de blog, une base de données d'enregistrements publics ou une simple application de sondage. Un projet est une collection de configurations et d'apps pour un site Web en particulier. Un projet peut contenir plusieurs apps. Une app peut être dans plusieurs projets différents.

Vos applications peuvent vivre n'importe où dans votre path Python . Dans ce tutoriel, nous créerons notre application de sondage juste à côté de votre fichier manage.py, il sera ainsi importé à son propre niveau de module, au lieu d'être un sous-module de mysite.

Pour créer votre application, assurez-vous d'être dans le même dossier que manage.py et tapez cette commande :

python manage.py startapp polls

Cela crée un dossier polls, dont le contenu ressemble à ça :

polls/
__init__.py
models.py
tests.py
views.py

Cette structure de dossier hébergera l'application poll.

Dans Django, la première étape dans l'écriture d'une application Web / base de données est de définir vos modèles -- principalement votre structure de base de donnés, avec des metadata supplémentaires.

Philosophie

Un modèle est la seule et unique source de données pour vos données. Le modèle contient les champs et comportements indispensables des données que vous allez enregistrer. Django suit le principe DRY . Cela consiste à définir votre modèle de données dans un seul endroit et d'en dériver automatiquement le reste.

Dans notre petite application poll, nous allons créer deux modèles : sondage et choix. Un sondage comporte une question et une date e publication. Un choix possède deux champs : le texte du choix et le décompte des votes. Chaque choix est associé à un sondage.

Ces concepts sont représentés avec une simple classe Python. Éditez le fichier polls/models.py pour qu'il ressemble à ceci :

from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
votes = models.IntegerField()

Le code est simple. Chaque modèle est représenté par une classe qui dérive de django.db.models.Model. Chaque modèle a un nombre donné de variables de classe, chacune d'elle représente un champ dans le modèle.

Chaque champ est représenté par une instance de la classe Field -- par exemple : CharField pour les champs caractères et DateTimeField pour les champs de type datetime. Cela indique à Django quel type de donnée est gérée par chaque champ.

Le nom de chaque instance de Field (par exemple: question ou pub_date ) est le nom du champ, dans un format machine-friendly. Vous utiliserez cette valeur dans votre code Python, et votre base de données l'utilisera comme nom de colonne.

Vous pouvez utiliser un argument optionnel à Field pour attribuer un nom humainement compréhensible. C'est utilisé dans quelques parties introspectives de Django, et double la documentation. Si ce champ n'est pas renseigné, Django utilisera le nom machine-readable. Dans cet exemple, nous n'avons défini qu'un nom humainement compréhensible, pour Poll.pub_date. Pour les autres champs du modèle, le nom de champ machine suffira comme nom humanisé.

Quelques classes Field ont des éléments obligatoires. Par exemple, CharField vous demande de fournir sa max_length. Ce n'est pas seulement utilisé dans le modèle de base de données, mais aussi en validation, comme nous allons bientôt le voir.

Enfin, vous noterez qu'une relation est définie, en utilisant ForeignKey. Cela indique à Django que chaque Choice est lié à un seul sondage. Django supporte toutes les relations habituelles des bases de données : plusieur à un, plusieurs à plusieurs et un à un.

Activer les modèles 

Ce petit bout de code modèle fournit un paque d'informations à Django. Avec, Djangoi est capable de ;

  • Créer un schéma de base de données (instructions CREATE TABLE ) pour cette application.
  • Créer l'API Python d'accès à la base de données, pour accèder aux objets Poll et Choice.

Mais nous devons d'abord dire à notre projet que l'application polls est installée.

Philosophie

Les applications Django sont "pluggables" : vous pouvez utiliser une application dans des projets différents, et vous pouvez distribuer les applications, parce qu'elles ne sont pas liées à une installation Django en particulier.

Éditez à nouveau le fichier settings.py et modifiez le paramètre INSTALLED_APPS pour lui ajouter la chaîne 'polls'. Le paramètre ressemblera à ceci :

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Décommentez la prochaine ligne pour activer admin:
# 'django.contrib.admin',
# Décommentez la prochaine ligne pour activer admin documentation:
# 'django.contrib.admindocs',
'polls',
)

Maintenant, Django sait qu'il doit inclure l'application polls. Exécutons uen autre commande :

python manage.py sql polls

Vous devriez voir quelque chose semblable à ce qui suit (les instrutions SQL CREATE TABLE pour l'application polls) :

BEGIN;
CREATE TABLE "polls_poll" (
"id" serial NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "polls_poll" ("id") DEFERRABLE INITIALLY DEFERRED,
"choice" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
COMMIT;

Quelques remarques :

  • L'affichage peut varier en fonction de la base de données que vous utilisez.
  • Le nom des tables sont générés automatiquement en combinant le nom de l'application (polls) et le nom en minuscules du modèle -- poll et choice. (Vous pouvez surcharger ce comportement.)
  • Les clés primaires (IDs) sont ajoutées automatiquement. (Vous pouvez également surcharger cela).
  • Par convention, Django ajjoute "_id" au nom de la clé étrangère. (Oui, vous pouvez également surcharger cela).
  • La relation avec la clé étrangère se fait explicitement par une instruction REFERENCES.
  • Tout est adapté à la base de données que vous utilisez, ainsi les champs spécifiques tels que auto_increment (MySQL), serial (PostgreSQL), ou integer primary key (SQLite) sont gérés pour vous automatiquement. Il en va de même pour le quotage des noms de champs -- par exemple, double guillemets ou guillemets simples. L'auteur de ce tutoriel utilise PostgreSQL, l'affichage de l'exemple est en syntaxe PostgreSQL.
  • La commande sql n'exécute pas le SQL dans votre base - il l'affiche seulement à l'écran pour que vous puissiez voir ce que le SQL de Django estime nécessaire. Si vous le voulez, vous pouvez copier et coller cet SQL à l'invite de commande de votre base de données. En tout état de cause, comme vous le verrez bientôt, Django fournit une façon aisée de commiter le SQL dans la base de données.

Si cela vous branche, exécutez également les commandes suivantes :

En regardant ce qu'affichent ces commandes, vous pouvez mieux comprendre ce qui se passe sous le capot.

Maintenant, lancez à nouveau syncdb pour créer les tables dans votre base de données :

python manage.py syncdb

La commande syncdb exécute sur votre base de données le SQL à partir de sqlall pour toutes les applis de INSTALLED_APPS qui n'existent pas déjà dans votre base de donénes. Elle crée toutes les tables, les données initiales, et les indexs pour toute application ajoutée à votre projet depuis la dernière exécution de syncdb. syncdb peut être appelé autant de fois que vous le voulez et il ne créera que les tables qui n'existent pas déjà.

Consultez la documentation django-admin.py pour toutes les infos sur ce que l'utilitaire manage.py peut faire.

Faire mumuse avec l'API ¶

Faisons maintenant un petit saut dans le shell interactif de Python et jouons avec l'API libre et gratuite que Django vous fournit. Pour obtenir l'invite du shell Python, utilisez cette commande :

python manage.py shell

Nous procédons ainsi plutôt que de taper simplement "python", parce que manage.py initialise la variable d'environnement DJANGO_SETTINGS_MODULE, qui donne à Django le path d'import de Python pour le fichier settings.py.

Outrepasser manage.py

Si vous ne voulez pas utiliser manage.py, pas de problème. Il suffit de paramétrer la variable d'environnement DJANGO_SETTINGS_MODULE à mysite.settings et lancez python à partir du dossier dans lequel manage.py se trouve (ou assurez-vous que ce dossier se trouve dans le path Python, pour que import mysite fonctionne).

Plus d'infos à ce sujet dans la documentation django-admin.py .

Une fois dans le shell, explorons avec l'API database :

>>> from polls.models import Poll, Choice # Import the model classes we just wrote.
# Pas encore de polls dans le système.
>>> Poll.objects.all()
[]
# Création d'un nouveau Poll.
# Le support des fuseaux horaires est activé dans le fichier settings par défaut, aussi
# Pour pub_date Django attend un datetime avec tzinfo. Utilisez timezone.now()
# à la place de datetime.datetime.now() et il fera ce qu'il faut.
>>> from django.utils import timezone
>>> p = Poll(question="What's new?", pub_date=timezone.now())
# Sauvegarder l'objet dans la base de données . Vous devez explicitement appeler save().
>>> p.save()
# Il a désormais un ID. Cela pourrait être "1L" au lieu de "1", selon 
# la base de données utilisée. Ce n'est pas crucial, cela veut simplement dire que 
# votre database backend préfère retourner les entiers en tant qu'entiers longs de Python
# objects.
>>> p.id
1
# Accès aux colonnes de la base via les attributs Python.
>>> p.question
"What's new?"
>>> p.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=)
# Modifie la valeur en modifiant les attributs, puis appeler save().
>>> p.question = "What's up?"
>>> p.save()
# objects.all() affiche tous les sondages dans la base de données.
>>> Poll.objects.all()
[]

Une minute. <Poll: Poll object> est, sans conteste, une représentation de l'objet qui n'apporte rien. Arrangeons cela en éditant le modèle polls (dans le fichier polls/models.py ) et en ajoutant une méthode __unicode__() à Poll et à Choice :

class Poll(models.Model):
# ...
def __unicode__(self):
return self.question
class Choice(models.Model):
# ...
def __unicode__(self):
return self.choice

Ajouter les méthodes __unicode__() à vos modèles est important, non seulement en ce qui concerne votre santé mentale lorsque vous avez affaire à l'invite intéractive, mais aussi parce que les représentations des objets sont utilisées dans l'interface admin automatiquement générée par Django..

Pourquoi __unicode__() et pas __str__() ?

Si vous êtes familier avec Python, vous avez peut-être l'habitude d'ajouter des méthodes __str__() à vos classes, et non des méthodes __unicode__(). Ici, nous utilisons __unicode__() parce les modèles Django traitent en Unicode par défaut. Toutes les données enregistrées dans votre base de données sont converties en Unicode en sortie.

Les modèles Django ont une méthode __str__() par défaut qui appelle __unicode__() et convertit le résultat en UTF-8 bytestring. Cela veut dire que unicode(p) va renvoyer une chaîne Unicode, et str(p) retournera une chaîne normale, avec ses caractères codés en UTF-8.

Si tout cela vous semble du charabia, rappelez-vous simplement d'ajouter les méthodes __unicode__() à vos modèles. Avec un peu de chance, tout se passera bien.

Notez que ce sont des méthodes Python tout à fait normales. Ajoutons une méthode personnalisée, juste pour la démo :

import datetime
from django.utils import timezone
# ...
class Poll(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Notez l'ajout de import datetime et de from django.utils import timezone, pour référencer le module Python standard datetime et les utilitaires time-zone de Django dans django.utils.timezone, respectivement. Si vous n'êtes pas familiers avec la gestion des time zone dans Python, vous pouvez en apprendre davantage dans les docs time zone support.

Savegardez ces modifications et démarrez un nouveau shell Python interactif en exécutant à nouveau python manage.py shell :

>>> from polls.models import Poll, Choice
# Assurons-nous que l'ajout de __unicode__() marche.
>>> Poll.objects.all()
[]
# Django fournit une copieuse API pour l'exploration des bases de données, entièrement pilotée par
# des arguments mots-clés.
>>> Poll.objects.filter(id=1)
[]
>>> Poll.objects.filter(question__startswith='What')
[]
# Obtenir le sondage dans l'année est 2012.
>>> Poll.objects.get(pub_date__year=2012)

>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Poll matching query does not exist.
# La recherche par la clé primaire est l'une des plus courantes, aussi Django fournit 
# un raccourci pour des recherches par clé primaire précises.
# Ce qui suit est identique à Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)

# Assurons-nous que notre méthode personnalisée marche.
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_recently()
True
# Ajouter quelques Choice à Poll. L'appel à create construit un nouvel
# objet object, effectue l'instruction INSERT, ajoute le choice à l'ensemble
# des choices disponibles et renvoie le nouvel objet Choice. Django crée
# un ensemble pour "l'autre côté" de la relation Clé étrangère
# (par exemple les choix d'un sondage) auquel on peut accèder via l'API.
>>> p = Poll.objects.get(pk=1)
# Affiche tout choix de l'ensemble objet en question -- rien pour l'instant.
>>> p.choice_set.all()
[]
# Crée trois choix.
>>> p.choice_set.create(choice='Not much', votes=0)

>>> p.choice_set.create(choice='The sky', votes=0)

>>> c = p.choice_set.create(choice='Just hacking again', votes=0)
# Les objets Choice ont un accès API aux objets Poll dont ils dépendent.
>>> c.poll

# Et réciproquement : les objets Poll ont un accès à leurs objets Choice.
>>> p.choice_set.all()
[, , ]
>>> p.choice_set.count()
3
# L'API suit automatiquement les relations aussi profondément que vous le voulez.
# Utilisez des doubles underscore pour séparer les relations.
# Cela marche quelque soit le niveau de profondeur; il n'y a pas de limites.
# Trouver tous les Choice de n'importe quel sondage dont pub_date est en 2012.
>>> Choice.objects.filter(poll__pub_date__year=2012)
[, , ]
# Effaçons l'un des choix. Pour cela on utilise delete().
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()

Pour plus d'infos sur le modèle relationnel, consultez Accessing related objects. Pour en savoir plus sur l'utilisation des doubles underscores pour effectuer des recherches via l'API, consultez Field lookups. Pour tous les détails sur l'API Base de données, consultez Database API reference.

Lorsque vous serez à l'aise avec l'API, lisez la partie 2 de ce tutoriel pour faire fonctionner l'admin automatic de Django.

Publicité
Publicité
1 2 > >>
Django Spirit
Publicité
Archives
Visiteurs
Depuis la création 5 055
Pages
Publicité