<< précédentsuivant >>

Chapitre 7 : Utilisation des formulaires

auteur invité : Simon Willison

Après avoir parcouru le chapitre précédent, vous devez à présent avoir un site complètement fonctionnel même s’il reste simple. Dans ce chapitre, nous allons aborder la prochaine pièce du puzzle : construire des vues qui récupèrent les entrées des utilisateurs.

Nous commencerons par faire un simple formulaire de recherche « à la main » et nous regarderons comment gérer les données soumises depuis le navigateur. À partir de là, nous utiliserons le framework des formulaires de Django.

Recherche

L’internet est une histoire de recherche. Deux des plus gros succès du net, Google et Yahoo, ont construit leur entreprise multi-millionaire autour de la recherche. La quasi majorité des sites voit une grosse part de leur trafic provenir ou aller vers ces pages de recherche. Souvent, la différence entre le succès et l’échec d’un site provient de la qualité de sa recherche. Il semblerait qu’il nous faille ajouter cette recherche à notre site de livres naissant, non ?

Nous commencerons par ajouter une vue « search » à notre URLconf (monsite.urls). Rappelez-vous que cela revient à ajouter quelque chose du genre (r'^search/$', 'monsite.books.views.search') au jeu de patrons d’URL.

Ensuite, nous écrirons cette vue search dans notre module view (mysite.books.views) :

from django.db.models import Q
    from django.shortcuts import render_to_response
    from models import Book

    def search(request):
        query = request.GET.get('q', '')
        if query:
            qset = (
                Q(title__icontains=query) |
                Q(authors__first_name__icontains=query) |
                Q(authors__last_name__icontains=query)
            )
            results = Book.objects.filter(qset).distinct()
        else:
            results = []
        return render_to_response("books/search.html", {
             "results": results,
            "query": query
        })

Il se passe une paire de chose ici, que vous n’avez pas encore vue. Tout d’abord, il y a request.GET. Voici comment vous avez accès aux données GET depuis Django. Les données POST sont accessibles au travers d’un objet request.POST similaire. Ces objets agissent exactement comme les dictionnaires standards de Python, avec quelques fonctionnalités supplémentaires détaillées à l’annexe H.

Que sont les données GET et POST ?

GET et POST sont les deux méthodes que les navigateurs utilisent pour envoyer des données à un serveur. La plupart du temps, vous les verrez dans les balises de formulaires HTML :

<form action="/books/search/" method="get">

Ceci permet au navigateur de soumettre les données du formulaires à l’URL /books/search/ en utilisant la méthode GET.

Il existe des différences importantes entre les sémantqiues de GET et POST que nous n’aborderons pas pour pour l’instant, mais vous pouvez consulter http://www.w3.org/2001/tag/doc/whenToUseGet.html si vous désirez en apprendre plus.

Donc la ligne :

query = request.GET.get('q', '')

cherche un paramètre GET nommé q et retourne une chaîne vide si ce paramètre n’a pas été soumis..

Notez que nous avons utilisés la méthode get() sur request.GET, ce qui porte potentiellement à confusion. Ici, la méthode get() est celle que possède chaque objet Python. Nous l’utilisons dans ce cas par précaution: il n’est pas sain de considérer ici que request.GET contient une clef 'q', nous utilisons donc get('q', '') pour fournir une valeur de substitution par défaut, '' (une chaîne vide). Si nous avions considérés la variable en utilisant request.GET['q'], ce code aurait levé une KeyError en cas d’absence du caractère q dans la donnée GET.

Ensuite, intéressons nous à ces histoires de Q (ndt: désolé pour le sous-entendu involontaire, ce sont les aléas de la traduction) - Les objets Q sont utilisés pour construire des requêtes complexes - dans le cas présent, nous recherchons les livres dont à la fois le titre ou le nom de l’un des auteurs correspondent à notre recherche. Techniquement, ces objets Q comprennent un QuerySet, et vous pouvez en lire plus à leur sujet dans l’annexe C.

Dans ces requêtes, icontains est une recherche insensible à la casse qui utilise l’opérateur SQL LIKE de la base sous-jacente.

Puisque nous effectuons la recherche dans un champ « plusieur à plusieur », il est possible que le même livre soit renvoyé plus d’une fois par la requête (par exemple, un livre dont les auteurs correspondent tous deux à notre recherche). Ajouter .distinct() au filtre de recherche élimine tous les doublons.

Toutefois, il nous manque toujours un gabarit pour cette vue « recherche ». Celui-ci devrait faire l’affaire :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
        <html lang="en">
        <head>
                <title>Search{% if query %} Results{% endif %}</title>
        </head>
        <body>
          <h1>Search</h1>
          <form action="." method="GET">
                <label for="q">Search: </label>
                <input type="text" name="q" value="{{ query|escape }}">
                <input type="submit" value="Search">
          </form>

          {% if query %}
                <h2>Results for "{{ query|escape }}":</h2>

                {% if results %}
                  <ul>
                  {% for book in results %}
                        <li>{{ book|escape }}</l1>
                  {% endfor %}
                  </ul>
                {% else %}
                  <p>No books found</p>
                {% endif %}
          {% endif %}
        </body>
        </html>

Espérons qu’à présent le résultat de ce code vous paraisse évident. Ceci dit, il y a quelques subtilités qui méritent éclaircissement :

  • L’action du formulaire est ., ce qui signifie « l’URL courante ». C’est une bonne pratique usuelle : n’utilisez pas de vues séparées pour la page de formulaire et pour la page des résultats ; utilisez une page unique qui serve à la fois le formulaire et les résultats de la recherche.

  • Nous réinjectons la valeur de la requête dans l’<input>. Ceci permet aux lecteurs d’affiner facilement leurs recherches sans avoir à resaisir ce qu’ils recherchaient.

  • Partout où query et book sont utilisés, nous utilisons le filtre escape pour nous assurer que toute recherche potentiellement dangereuse soit filtrée avant d’être insérée dans la page.

    Il est vital de faire cela avec tous les contenus soumis par les utilisateurs ! Sinon, vous ouvrez votre site aux attaques du type cross-site scripting (XSS). Le chapitre 19 aborde le XSS et la sécurité plus en détail.

  • Cependant, nous n’avons pas besoin de nous soucier des contenus préjudiciables dans les requêtes vers la base de données - nous pouvons simplement passer la requête en l’état dans la recherche. Pour la simple raison que la couche base de données de Django s’occupe de cet aspect de la sécurité à votre place.

À présent, nous avons une recherche fonctionnelle. Une amélioration supplémentaire consisterait à ajouter un formulaire de recherche sur chaque page (c’est à dire, dans le gabarit de base) ; Nous vous laissons gérer cela par vous même.

Ensuite, nous allons étudier un exemple plus complexe. Mais avant cela, discutons d’un sujet plus abstrait: le « formulaire parfait ».

Le « formulaire parfait »

Les formulaires peuvent souvent être une cause majeure de frustation pour les utilisateurs de votre site. Considérons les fonctionnalités d’un hypothétique formulaire parfait :

  • Il doit demander à l’utilisateur quelques informations, évidemment. L’accessibilité et l’ergonomie sont ici déterminantes, l’utilisation judicieuse de l’élément HTML <label> et de l’aide contextuelle sont donc importantes.
  • Les données soumises doivent être sujettes à une vérifiaction extensive. La règle d’or de la sécurité des applications web est de « ne jamais avoir confiance en les données entrantes », la validation est donc essentielle.
  • Si l’utilisateur a fait une erreur quelconque, le formulaire doit être réaffiché avec des messages d’erreur significatifs. Les données originales doivent êtres préchargées, pour éviter à l’utilisateur d’avoir à tout saisir de nouveau.
  • Le formulaire doit continuer à s’afficher jusqu’à ce que tout les champs aient été correctement remplis.

Construire le formulaire parfait semble être un gros travail ! Heureusement, le framework pour les formulaires sous Django est conçu pour faire la plupart du travail à votre place. Vous fournissez une description des champs du formulaire, les règles de validation, un simple gabarit, et Django s’occupe du reste. Le résultat est un « formulaire parfait » avec un minimum d’effort.

Créer un formulaire de commentaires

La meilleure façon de construire un site que les gens aiment est d’écouter leurs réactions. Beaucoup de sites semblent avoir oublié cela ; Ils cachent les détails de contact derrière des couches de FAQs, et semblent rendre le plus difficile possible le contact avec un être humain.

Quand votre site à des millions d’utilisateurs, ce peut être une stratégie raisonnable. Lorsque vous essayez de construire une audience, cependant, vous devez activement encourager toute opportunité de réagir. Fabriquons un simple formulaire de commentaire et utilisons le pour montrer le framework Django en action.

Nous commencerons par ajouter (r'^contact/$','monsite.books.views.contact') à l’URLconf, pour définir ensuite notre formulaire. Les formulaires sous Django sont crées de façon similaire à celle des modèles: déclarativement, en utilisant une classe Python. Voici la classe de notre simple formulaire. Par convention, nous l’ajouterons à un nouveau fichier forms.py placé dans le répertoire de notre application:

from django import newforms as forms

TOPIC_CHOICES = (
    ('general', 'General enquiry'),
    ('bug', 'Bug report'),
    ('suggestion', 'Suggestion'),
)

class ContactForm(forms.Form):
    topic = forms.ChoiceField(choices=TOPIC_CHOICES)
    message = forms.CharField()
    sender = forms.EmailField(required=False)

“New” Forms ? Quoi ?

Lorsque Django fut pour la première fois diffusé auprès du public, il avait un système de formulaires compliqué, confus. Il rendait la production des formulaires beaucoup trop difficile, alors il fut complétement réécrit et se nomme à présent « newforms ». Cependant, il reste une bonne partie de code qui dépend de l’« ancien » système, c’est pourquoi Django fournit pour l’instant les deux paquets relatifs aux formulaires.

Pour l’écriture de ce livre, l’ancien système de formulaire de Django reste django.forms alors que le nouveau paquet des formulaires est django.newforms. Puis viendra le temps de changer et django.forms pointera alors vers le nouveau paquet de formulaire. Quoiqu’il en soit, pour s’assurer que les exemples de ce livre fonctionnent le plus largement possible, tous les exemples se référeront à django.newforms.

Un formulaire Django est une sous-classe de django.newforms.Form, tout comme un modèle Django est une sous-classe de django.db.models.Model. Le module django.newforms contient aussi de nombreuses classes``Field`` ; une liste complète est disponible dans la documentation de Django à l’adresse http://www.djangoproject.com/documentation/0.96/newforms/.

Notre ContactForm se compose de trois champs : un thème, qui est un choix parmi trois options ; un message, qui est un champ textuel ; et un expéditeur, qui est un champ de courriel et reste optionnel (parce que même un commentaire anonyme peut être utile). Il y a de nombreux autres types de champs disponibles, et vous pouvez écrire le votre s’ils ne couvrent pas vos besoins.

L’objet formulaire en lui même sait comment faire un certain nombre de choses utiles. Il peut valider une collection de données, il peut générer ses propres « widgets » HTML, il peut construire un jeu de messages d’erreur fort utile et, si nous sommes fainéants, il peut même faire l’intégralité du formulaire pour nous. Attachons le à une vue et voyons le en action. Dans views.py:

from django.db.models import Q
from django.shortcuts import render_to_response
from models import Book
**from forms import ContactForm**

def search(request):
    query = request.GET.get('q', '')
    if query:
        qset = (
            Q(title__icontains=query) |
            Q(authors__first_name__icontains=query) |
            Q(authors__last_name__icontains=query)
        )
        results = Book.objects.filter(qset).distinct()
    else:
        results = []
    return render_to_response("books/search.html", {
        "results": results,
        "query": query
    })

**def contact(request):**
    **form = ContactForm()**
    **return render_to_response('contact.html', {'form': form})**

et dans contact.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>Contact us</title>
</head>
<body>
    <h1>Contact us</h1>
    <form action="." method="POST">
        <table>
            {{ form.as_table }}
        </table>
        <p><input type="submit" value="Submit"></p>
    </form>
</body>
</html>

La ligne la plus intéressante ici est {{ form.as_table }}. form est notre instance de ContactForm, celle passée à render_to_response. as_table est une méthode de cet objet qui retourne le formulaire sous la forme d’une séquence de lignes d’un tableau (as_ul et as_p peuvent aussi être utilisées). Le HTML généré ressemble à ceci :

<tr>
    <th><label for="id_topic">Topic:</label></th>
    <td>
        <select name="topic" id="id_topic">
            <option value="general">General
            enquiry</option>
            <option value="bug">Bug report</option>
            <option
            value="suggestion">Suggestion</option>
        </select>
    </td>
</tr>
<tr>
    <th><label for="id_message">Message:</label></th>
    <td><input type="text" name="message" id="id_message" /></td>
</tr>
<tr>
    <th><label for="id_sender">Sender:</label></th>
    <td><input type="text" name="sender" id="id_sender" /></td>
</tr>

Notez que les balises <table> et <form> ne sont pas incluses ; vous devez les définir vous même dans le gabarit, ce qui vous donne le contrôle sur la façon dont se comporte le formulaire lorsqu’il est validé. Les éléments de libéllés sont inclus, rendant les formulaires directement disponibles.

Notre formulaire utilise actuellement un widget <input type="text"> pour le champ du message. Nous ne voulons pas restreindre nos utilisateurs à une seule ligne de texte, alors nous le remplaçons par un widget <textarea> :

class ContactForm(forms.Form):
    topic = forms.ChoiceField(choices=TOPIC_CHOICES)
    message = forms.CharField(**widget=forms.Textarea()**)
    sender = forms.EmailField(required=False)

Le framework de formulaire déplace la logique de présentation de chacun des champs dans un jeu de widgets. Chaque type de champ possède un widget par défaut, mais vous pouvez facilement outrepasser cette fonctionnalité, ou fournir un widget personnalisé de votre cru.

À cet instant, valider le formulaire ne fait, à vrai dire, rien. Ajoutons lui nos règles de validation :

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
    else:
        form = ContactForm()
    return render_to_response('contact.html', {'form': form})

Une instance de formulaire peut avoir l’un de ces deux états : lié ou non. Une instance liée (bound) est construite à partir d’un dictionnaire (où d’un objet semblable à un dictionnaire) et sait comment valider et réafficher les données de celui-ci. Un formulaire non lié (unbound) n’a pas de données qui lui sont associées et sais uniquement comment s’afficher lui même.

Essayer de cliquez sur le Submit d’un formulaire vierge. La page doit se raffraîchir, affichant une erreur de validation nous informant que le champs message est requis.

Essayer aussi de saisir une adresse invalide. EmailField sait comment valider une adresse de courrier électronique, au moins jusqu’à un niveau de doute raisonnable.

Configurer les données initales

Passer directement les données au constructeur de formulaire lies ces données et indique que la validation doit être faite. Souvent, cependant, nous avons besoin d’afficher un formulaire initial avec certains de champs préremplis. - par exemple, un formulaire « éditez ». Nous pouvons faire cela avec l’argument clef initial :

form = CommentForm(initial={'sender': 'user@example.com'})

Si notre formulaire utilise à l’avenir toujours les mêmes valeurs par défaut, nous pouvons les configurer dans la définition même du formulaire:

message = forms.CharField(widget=forms.Textarea(),**initial="Replace with your feedback"**)

Gérer la validation

Une fois que l’utilisateur a rempli le formulaire de sorte qu’il franchise nos règles de validation, nous devons faire quelque chose d’utile de ces données. Dans notre cas, nous voulons préparer puis envoyer un courriel contenant la remarque de l’utilisateur. Nous utiliserons le module de courrier fournit par Django pour ce faire.

Toutefois, nous avons d’abord besoin de savoir si les données sont effectivement valables, et si c’est le cas, nous avons besoin d’accéder aux données validées. Le framework de formulaires fait plus que valider les données, il les convertit aussi en type Python. Notre formulaire de contact ne gère que les chaines de caractères, mais si nous avions utilisé un IntegerField ou un DateTimeField, le framework des formulaires nous assurerait l’obtention d’un entier Python ou d’un objet datetime, respectivement.

Pour savoir si le formulaire est lié à des données valides ou pas, appelez la méthode is_valid() :

form = ContactForm(request.POST)
if form.is_valid():
    # Process form data

À présent nous devons accéder aux données. Nous pourrions les extraire directement de request.POST, mais ce faisant, nous passerions à côté des conversions effectuées par le framework de formulaires Au lieu de cela, nous utilisons form.cleaned_data:

if form.is_valid():
    topic = form.cleaned_data['topic']
    message = form.cleaned_data['message']
    sender = form.cleaned_data.get('sender', 'noreply@example.com')
    # ...

Notez que puisque sender n’est pas un champ requis, nous fournissons une valeur par défaut lorsque celle-ci manque. Finalement, nous devons enregistrer le retour utilisateur. La façon la plus simple de faire cela est de l’envoyer à un administrateur du site. Nous pouvons le faire en utilisant la fonction send_mail :

from django.core.mail import send_mail

# ...

send_mail(
    'Feedback from your site, topic: %s' % topic,
    message, sender,
    ['administrator@example.com']
)

La fonction send_mail nécessite quatre arguments: le sujet du courriel, le corps du texte, l’adresse du « formulaire », ainsi qu’une liste d’adresses destinataires. send_mail est une encapsulation de la classe Django EmailMessage, fournissant des fonctionnalités avancées tels que les pièces jointes, les courriers composés, et un contrôle complet des en-têtes de courrier.

Après avoir envoyé notre courriel, nous redirigerons notre utilisateur vers une page statique de confirmation. La fonction view terminée ressemble à ceci :

from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.core.mail import send_mail
from forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            topic = form.cleaned_data['topic']
            message = form.cleaned_data['message']
            sender = form.cleaned_data.get('sender',
            'noreply@example.com')
            send_mail(
                'Feedback from your site, topic: %s'
                % topic,
                message, sender,
                ['administrator@example.com']
            )
            return
            HttpResponseRedirect('/contact/thanks/')
    else:
        form = ContactForm()
    return render_to_response('contact.html', {'form': form})

Redirection après POST

Si un utilisateur choisit de rafraîchir la page qui était affichée par une requête POST, cette requête sera répétée. Ceci peut souvent amener à un comportement indésirable, tel qu’un doublon d’enregistrement ajouté à la base de données. La redirection après un POST est un patron utile qui peut vous éviter ce scénario: après qu’un POST ait été soumis avec succès, redirigez l’utilisateur vers une autre page plutôt que de lui retourner directement le HTML.

Personnalisation des règles de validation

Imaginez que nous ayons activé notre formulaire de feedback, et que les courriels commencent à tomber. Il reste juste un problème : certain courriels ne comportent qu’un ou deux mots, insuffisant pour une demande détaillée. Nous décidons d’adopter une nouvelle politique : quatre mots au minimum, s’il vous plaît.

Il existe de multiples façons d’accrocher une validation personnalisée à un formulaire de validation sous Django. Si notre règle s’avère utilisée encore et encore, nous pouvons créer un type de champ personnalisé. La plupart des validations étant à usage unique, elles peuvent donc êtres ajoutées directement à la classe de formulaire.

Nous voulons une validation supplémentaire sur le champ message, nous avons donc besoin d’ajouter une méthode clean_message` à notre formulaire :

class ContactForm(forms.Form):
    topic = forms.ChoiceField(choices=TOPIC_CHOICES)
    message = forms.CharField(widget=forms.Textarea())
    sender = forms.EmailField(required=False)

    def clean_message(self):
        message = self.cleaned_data.get('message', '')
        num_words = len(message.split())
        if num_words < 4:
            raise forms.ValidationError("Not enough
            words!")
        return message

Cette nouvelle méthode sera appellée après le validateur par défaut (dans le cas présent, le validateur de CharField requis). Parce que le champ de données à déjà été partiellement traité, nous devons l’enlever du dictionnaire cleaned_data appartenant au formulaire.

Nous avons naïvement utilisé une combinaison de len() et de split() pour compter le nombre de mots. Si l’utilisateur à saisit trop peu de mots, nous levons une ValidationError. La chaîne de caractère attachée à cette exception sera affichée à l’utilisateur en tant qu’élément de la liste d’erreur.

Il est important d’avoir retourné explicitement la valeur du champ à la fin de la méthode. Ceci nous permet de modifier la valeur (ou de la convertir vers un type Python différent) à l’intérieur de notre méthode de validation personnalisée. Si nous oublions cette instruction de retour, alors None sera renvoyé, et la valeur d’origine sera perdue.

Une ergonomie personnalisée

La façon la plus rapide de personnaliser la présentation d’un formulaire passe par les CSS. En particulier la liste des erreurs qui peut être faite avec quelques mises en valeur visuelles, grâce à la balise <ul> qui possèdent un attribut de classe errorlist précisément pour cet usage. La CSS qui suit met concrétement les erreurs en évidence :

<style type="text/css">
    ul.errorlist {
        margin: 0;
        padding: 0;
    }
    .errorlist li {
        background-color: red;
        color: white;
        display: block;
        font-size: 10px;
        margin: 0 0 3px;
        padding: 4px 5px;
    }
</style>

Même s’il est pratique d’avoir les formulaires HTML générés pour nous, dans la plupart des cas le rendu par défaut ne conviendra pas à notre application. {{ form.as_table}} et compagnie sont des raccourcis utiles lorsque nous développons notre application, mais tout ce qui concerne la façon dont s’affiche un formulaire peut être outrepassé, principalement à l’intérieur du gabarit lui même.

Chaque widget de champs (<input type="text">, <select>, <textarea>, ou similaires) peut être rendu individuellement en accédant à {{ form.fieldname }}. Toutes les erreurs associées à un champ sont disponibles en tant que {{form.fieldname.errors }}. Nous pouvons utiliser ces variables de formulaire pour créer un gabarit personnalisé destiné à notre formualire de contact :

<form action="." method="POST">
    <div class="fieldWrapper">
        {{ form.topic.errors }}
        <label for="id_topic">Kind of feedback:</label>
        {{ form.topic }}
    </div>
    <div class="fieldWrapper">
        {{ form.message.errors }}
        <label for="id_message">Your message:</label>
        {{ form.message }}
    </div>
    <div class="fieldWrapper">
        {{ form.sender.errors }}
        <label for="id_sender">Your email (optional):</label>
        {{ form.sender }}
    </div>
    <p><input type="submit" value="Submit"></p>
</form>

{{ form.message.errors }} s’affichera sous la forme d’une <ul class="errorlist"> si des erreurs sont présentes et par une chaîne de caractères vide si le champ est valide (ou si le formulaire n’est pas lié). Nous pouvons aussi traiter les form.message.errors comme des Booleéns ou même les parcourirs comme des listes, par exemple :

<div class="fieldWrapper{% if form.message.errors %} errors{% endif %}">
    {% if form.message.errors %}
        <ol>
        {% for error in form.message.errors %}
            <li><strong>{{ error|escape }}</strong></li>
        {% endfor %}
        </ol>
    {% endif %}
    {{ form.message }}
</div>

Dans le cas d’erreurs de validation, cela ajoutera une classe « erreurs » à la balise <div> contenante et affichera la liste des erreurs dans une liste ordonnée.

Créer des formulaires à partir de gabarits

Construisons quelque chose d’un peu plus intéressant : un formulaire qui soumet un nouvel éditeur à notre application livre du chapitre 5.

Un principe important du développement logiciel que Django tente de respecter est Don’t Repeat Yourself (DRY), ne vous répétez pas. Andy Hunt et Dave Thomas, dans The Pragmatic Programmer définnissent cela de la façon suivante :

Chaque composant du savoir doit avoir une représentation unique, univoque, et faisant autorité au sein d’un système.

Notre classe de modèle Publisher indique qu’un éditeur possède un nom, une adresse, une ville, un département, un pays et un site web. Dupliquer cette information dans la définition d’un formulaire briserait la règle du DRY. Au lieu de cela , nous pouvons utiliser un raccourcis très utile : form_for_model():

from models import Publisher
from django.newforms import form_for_model

PublisherForm = form_for_model(Publisher)

PublisherForm est une sous-classe de Form, tout comme la classe ContactForm qui fut créée manuellement un peu plus tôt. Nous pouvons l’utiliser de la même façon :

from forms import PublisherForm

def add_publisher(request):
    if request.method == 'POST':
        form = PublisherForm(request.POST)
        if form.is_valid():
            form.save()
            return
            HttpResponseRedirect('/add_publisher/thanks/')
    else:
        form = PublisherForm()
    return render_to_response('books/add_publisher.html',
    {'form': form})

Le fichier add_publisher.html est à peu de chose prêt identique à notre gabarit contact.html d’origine, il a donc été omis. Souvenez vous aussi d’ajouter un nouveau patron à l’URLconf: (r'^add_publisher/$','monsite.books.views.add_publisher').

Il y a un raccourcis supplémentaire employé ici. Puisque les formulaires dérivés des modèles sont souvent utilisés pour enregistrer de nouvelles instances de modèle dans la base de données, la classe formulaire créée par form_for_model inclut une méthode save() très pratique. Il s’agit du cas courant ; vous êtes invités à l’ignorer si vous voulez faire quelque chose d’un peu plus compliqué avec les données soumises.

form_for_instance() est une méthode liée qui peut créer un formulaire prédéfini à partir d’une instance de classe d’un modèle. Ceci est pratique pour créer des formulaires d’« édition ».

Et ensuite ?

Ce chapitre conclu l’introduction de ce livre. Les 13 chapitres suivants abordent les sujets avancés, y compris la génération de contenu autre que le HTML (Chapitre 11), la sécurité (Chapitre 19), et le déploiement (Chapitre 20).

À l’issue de ces sept premiers chapitres, vous devriez en savoir suffisament pour commencer à écrire vos propres projets Django. Le reste du livre vous aidera à combler les pièces manquantes au fil de vos besoins.

Nous commencerons le Chapitre 8 par revenir en arrière et étudier d’un peu plus près les vues et les URLconfs (introduits tout d’abord au Chapitre 3).

<< précédentsuivant >>

Dernière modification: 2010-05-10 17:30:40.941024