Vous pouvez bien sûr conserver la structure de base qui est d'avoir un ensemble de créatures et/ou de personnages, et un ensemble de lieux avec des fonctions différentes (par exemple, pour un centre d'entrainement : terrain de foot, cantine, salle de muscu, dortoir). Il peut y avoir des variantes : Pour une maison des poupées il peut y avoir plusieurs chambres, une pièce commune, un jardin et une terrasse. Laissez libre cours à votre imagination.
Vous pouvez bien sûr conserver la structure de base qui est d'avoir un ensemble de créatures et/ou de personnages, et un ensemble de lieux avec des fonctions différentes (par exemple, pour un centre d'entrainement : terrain de foot, cantine, salle de muscu, dortoir). Il peut y avoir des variantes : Pour une maison des poupées il peut y avoir plusieurs chambres, une pièce commune, un jardin et une terrasse. Laissez libre cours à votre imagination.
-
Les créatures passent par différents états au cours de la journée en fonction des lieux qu'ils visitent.
+
Les personnages passent par différents états au cours de la journée en fonction des lieux qu'ils visitent.
<note tip> ** Rappel **
<note tip> ** Rappel **
-
Reprenez cette structure de données de type ''Animal'' -- ''Equipement'' utilisée dans les TD précédents
+
Reprenez cette structure de données de type ''Personnage'' -- ''Equipement'' utilisée dans les TD précédents
lieu = models.ForeignKey(Equipement, on_delete=models.CASCADE)
lieu = models.ForeignKey(Equipement, on_delete=models.CASCADE)
def __str__(self):
def __str__(self):
-
return self.id_char
+
return self.id_character
</code>
</code>
Vous deviez obtenir une interface simple de ce type:
Vous deviez obtenir une interface simple de ce type:
+
{{ :public:appro-s7:simple-hamster.png?600 |}}
{{ :public:appro-s7:simple-hamster.png?600 |}}
Ligne 71:
Ligne 71:
Vous pouvez exploiter les photos qui sont définies dans les attributs du modèle pour obtenir par exemple:
Vous pouvez exploiter les photos qui sont définies dans les attributs du modèle pour obtenir par exemple:
-
{{ :public:appro-s7:screenshot.png?500 |}}
+
{{ :public:appro-s7:animalerie_web.png?800 |}}
==== Formulaires Django ====
==== Formulaires Django ====
Ligne 98:
Ligne 98:
fields = ('lieu',)
fields = ('lieu',)
</code>
</code>
-
<html>
+
Tout d'abord, nous avons besoin d'importer les formulaires Django (''from django import forms''), puis notre modèle Character (''from .models import Character'').
-
<p>Tout d'abord, nous avons besoin d'importer les formulaires Django (<code>from django import forms</code>), puis notre modèle <code>Character</code> (<code>from .models import Character</code>).</p>
+
-
<p>Comme vous l'avez probablement deviné, <code>MoveForm</code> est le nom de notre formulaire. Nous avons besoin d'indiquer à Django que ce formulaire est un <code>ModelForm</code> (pour que Django fasse certaines choses automatiquement pour nous). Pour cela, nous utilisons <code>forms.ModelForm</code>.</p>
+
Comme vous l'avez probablement deviné, ''MoveForm'' est le nom de notre formulaire. Nous avons besoin d'indiquer à Django que ce formulaire est un ModelForm (pour que Django fasse certaines choses automatiquement pour nous). Pour cela, nous utilisons ''forms.ModelForm''.
-
<p>Ensuite, nous avons la <code>class Meta</code> qui nous permet de dire à Django quel modèle il doit utiliser pour créer ce formulaire (<code>model = Character</code>).</p>
+
-
<p>Enfin, nous précisions quel⋅s sont le⋅s champ⋅s qui doivent figurer dans notre formulaire. Dans notre cas, nous souhaitons que seul le <code>lieu</code> apparaisse dans notre formulaire. </p>
+
Ensuite, nous avons la class Meta qui nous permet de dire à Django quel modèle il doit utiliser pour créer ce formulaire (''model = Character'').
-
<p>Et voilà, c'est tout ! Tout ce qu'il nous reste à faire, c'est d'utiliser ce formulaire dans une <em>vue</em> et de l'afficher dans un template.</p>
+
-
<p>Nous allons donc une nouvelle fois suivre le processus suivant et créer : un lien vers la page, une URL, une vue et un template.</p>
+
Enfin, nous précisions quel⋅s sont le⋅s champ⋅s qui doivent figurer dans notre formulaire. Dans notre cas, nous souhaitons que seul le lieu apparaisse dans notre formulaire.
-
</html>
+
+
Et voilà, c'est tout ! Tout ce qu'il nous reste à faire, c'est d'utiliser ce formulaire dans une vue et de l'afficher dans un template.
+
+
Nous allons donc une nouvelle fois suivre le processus suivant et créer : un lien vers la page, une URL, une vue et un template.
==== Lien vers une page contenant le formulaire ====
==== Lien vers une page contenant le formulaire ====
-
Il est temps d'ouvrir playground/templates/playground/base.html dans l'éditeur de code et ajouter un lien vers la vue ''character_detail''.
+
Il est temps d'ouvrir ''playground/templates/playground/base.html'' dans l'éditeur de code et ajouter un lien vers la vue ''character_detail''.
<p>Ouvrez maintenant le fichier <code>playground/views.py</code> dans l'éditeur de code et ajoutez les lignes suivantes avec celles du <code>from</code> qui existent déjà :</p>
+
Ouvrez maintenant le fichier ''playground/views.py'' dans l'éditeur de code et ajoutez les lignes suivantes avec celles du ''from'' qui existent déjà :
-
</html>
+
<code python>
<code python>
from django.shortcuts import render, get_object_or_404, redirect
from django.shortcuts import render, get_object_or_404, redirect
<p>Afin de pouvoir créer un nouveau formulaire <code>Move</code>, nous avons besoin d'appeler la fonction <code>MoveForm()</code> et de la passer au template. Nous reviendrons modifier cette <em>vue</em> plus tard, mais pour l'instant, créons rapidement un template pour ce formulaire.</p>
+
Afin de pouvoir créer un nouveau formulaire ''Move'', nous avons besoin d'appeler la fonction ''MoveForm()'' et de la passer au template. Nous reviendrons modifier cette //vue// plus tard, mais pour l'instant, créons rapidement un template pour ce formulaire.
-
</html>
==== Template ====
==== Template ====
-
<html>
+
Nous avons à présent besoin de créer un fichier ''character_detail.html'' dans le dossier ''playground/templates/playground'' et de l'ouvrir dans l'éditeur de code. Afin que notre formulaire fonctionne, nous avons besoin de plusieurs choses :
-
<p>Nous avons à présent besoin de créer un fichier <code>character_detail.html</code> dans le dossier <code>playground/templates/playground</code> et de l'ouvrir dans l'éditeur de code. Afin que notre formulaire fonctionne, nous avons besoin de plusieurs choses :</p>
+
-
<ul>
+
- Nous avons besoin d'afficher le formulaire. Pour cela, nous n'avons qu'à utiliser ''{{ form.as_uk }}''.
-
<li>Nous avons besoin d'afficher le formulaire. Pour cela, nous n'avons qu'à utiliser <code>{{ form.as_uk }}</code>.</li>
+
- La ligne précédente va avoir besoin d'être entourée des balises HTML ''<form method="POST">...</form>''.
-
<li>La ligne précédente va avoir besoin d'être entourée des balises HTML <code><form method="POST">...</form></code>.</li>
+
- Nous avons besoin d'un bouton ''Valider''. Nous allons le créer à l'aide d'un bouton HTML : ''<button type="submit">Valider</button>''.
-
<li>Nous avons besoin d'un bouton <code>Valider</code>. Nous allons le créer à l'aide d'un bouton HTML : <code><button type="submit">Valider</button></code>.</li>
+
- Enfin, nous devons ajouter ''{% csrf_token %}'' juste après ''<form ...>''. C'est très important car c'est ce qui va permettre de sécuriser votre formulaire ! Si vous oubliez ce détail, Django se plaindra lorsque vous essaierez de sauvegarder le formulaire:
-
<li>Enfin, nous devons ajouter <code>{% csrf_token %}</code> juste après <code><form ...></code>. C'est très important car c'est ce qui va permettre de sécuriser votre formulaire ! Si vous oubliez ce détail, Django se plaindra lorsque vous essaierez de sauvegarder le formulaire:</li>
Ok, voyons maintenant à quoi devrait ressembler le HTML contenu dans le fichier ''character_detail.html'' :
-
<p>Ok, voyons maintenant à quoi devrait ressembler le HTML contenu dans le fichier <code>character_detail.html</code> :
+
-
</html>
+
<code html>
<code html>
{% extends 'playground/base.html' %}
{% extends 'playground/base.html' %}
Ligne 190:
Ligne 191:
{% endblock %}
{% endblock %}
</code>
</code>
-
<html>
+
-
<p>Rafraîchissons la page ! Et voilà : le formulaire s'affiche sous la forme d'une liste d'options!</p>
+
Rafraîchissons la page ! Et voilà : le formulaire s'affiche sous la forme d'une liste d'options!
-
<p>Mais attendez une minute! Lorsque vous sélectionnez une option, que se passera-t-il?</p>
+
+
Mais attendez une minute! Lorsque vous sélectionnez une option, que se passera-t-il?
Rien!
Rien!
-
Retournons à notre <em>vue</em>.</p>
+
Retournons à notre //vue//.
-
</html>
+
==== Sauvegarder le contenu du formulaire ====
==== Sauvegarder le contenu du formulaire ====
-
<html>
+
-
<p>Ouvrez à nouveau <code>blog/views.py</code> dans l'éditeur de code. Actuellement, <code>post_new</code> n'est composé que des lignes de code suivantes :</p>
+
Ouvrez à nouveau ''blog/views.py'' dans l'éditeur de code. Actuellement, ''post_new'' n'est composé que des lignes de code suivantes :
-
</html>
+
<code python>
<code python>
def character_detail(request, id_character):
def character_detail(request, id_character):
Ligne 210:
Ligne 212:
</code>
</code>
-
<html>
+
-
<p>Lorsque nous envoyons notre formulaire, nous revenons à la même vue. Cependant, nous récupérons les données dans <code>request</code>, et plus particulièrement dans <code>request.POST</code>. Vous rappelez-vous comment dans le fichier HTML, notre définition de la variable <code><form></code> avait la méthode <code>method="POST"</code>? Tous les champs du formulaire se trouvent maintenant dans <code>request.POST</code>. Veillez à ne pas renommer <code>POST</code> en quoi que ce soit d'autre : la seule autre valeur autorisée pour <code>method</code> est <code>GET</code>. Malheureusement, nous n'avons pas le temps de rentrer dans les détails aujourd'hui.</p>
+
Lorsque nous envoyons notre formulaire, nous revenons à la même vue. Cependant, nous récupérons les données dans ''request'', et plus particulièrement dans ''request.POST''. Vous rappelez-vous comment dans le fichier HTML, notre définition de la variable ''form'' avait la méthode ''method=POST''? Tous les champs du formulaire se trouvent maintenant dans ''request.POST''. Veillez à ne pas renommer ''POST'' en quoi que ce soit d'autre : la seule autre valeur autorisée pour ''method'' est ''GET''. Malheureusement, nous n'avons pas le temps de rentrer dans les détails aujourd'hui.
-
<p>Donc dans notre <em>vue</em> nous avons deux situations différentes à gérer : la première quand on accède à la page pour la première fois et nous voulons un formulaire vide, et la seconde quand on revient à la <em>vue</em> avec les données que l'on a saisies dans le formulaire. Pour gérer ces deux cas, nous allons utiliser une condition
+
-
</html>
+
Donc dans notre //vue// nous avons deux situations différentes à gérer : la première quand on accède à la page pour la première fois et nous voulons un formulaire vide, et la seconde quand on revient à la //vue// avec les données que l'on a saisies dans le formulaire. Pour gérer ces deux cas, nous allons utiliser une condition
<code python>
<code python>
Ligne 222:
Ligne 225:
</code>
</code>
-
<html>
+
-
<p>Il faut maintenant remplir à l'endroit des pointillés <code>[...]</code>. Si <code>method</code> contient <code>POST</code> alors on veut construire le <code>MoveForm</code> avec les données du formulaire, n'est-ce pas ? Nous allons le faire comme cela :
+
Il faut maintenant remplir à l'endroit des pointillés ''[...]''. Si ''method'' contient ''POST'' alors on veut construire le ''MoveForm'' avec les données du formulaire, n'est-ce pas ? Nous allons le faire comme cela :
</html>
</html>
<code python>
<code python>
form = MoveForm(request.POST, instance=character)
form = MoveForm(request.POST, instance=character)
</code>
</code>
-
<html>
+
-
<p>La prochaine étape est de vérifier que le formulaire a été rempli correctement (tous les champs obligatoires ont été remplis et aucune valeur incorrecte n'a été envoyée). Nous allons faire ça en utilisant <code>form.is_valid()</code>.</p>
+
La prochaine étape est de vérifier que le formulaire a été rempli correctement (tous les champs obligatoires ont été remplis et aucune valeur incorrecte n'a été envoyée). Nous allons faire ça en utilisant ''form.is_valid()''.
-
<p>Testons donc si notre formulaire est valide et, si c'est le cas, sauvegardons-le !</p>
+
-
</html>
+
Testons donc si notre formulaire est valide et, si c'est le cas, sauvegardons-le !
<code python>
<code python>
if form.is_valid():
if form.is_valid():
Ligne 243:
Ligne 247:
</code>
</code>
-
<html>
-
<p>En gros, nous effectuons deux choses ici : nous sauvegardons le nouvel état du personnage grâce à <code>form.save</code> et nous mettons à jour l'occupation des lieux. Rappelez vous, tout déplacement du personnage s'acccompagne d'un changement d'occupation. Nous devons également modifier les lieux. <code>ancien_lieu.save()</code> et <code>nouveau_lieu.save()</code> sauvegarderont les changements. Et voilà, la mise à jour est enregistrée !</p>
-
<p>Enfin, ce serait génial si nous pouvions tout de suite aller à la page <code>character_detail</code> avec le contenu que nous venons de créer. Pour cela, nous avons besoin d'importer une dernière chose :
-
<p>Maintenant, nous allons ajouter la ligne qui signifie "aller à la page <code>character_detail</code> pour le changement qui vient d'être enregistré</p>
+
En gros, nous effectuons deux choses ici : nous sauvegardons le nouvel état du personnage grâce à ''form.save'' et nous mettons à jour l'occupation des lieux. Rappelez vous, tout déplacement du personnage s'acccompagne d'un changement d'occupation. Nous devons également modifier les lieux. ''ancien_lieu.save()'' et ''nouveau_lieu.save()'' sauvegarderont les changements. Et voilà, la mise à jour est enregistrée !
-
</html>
+
+
Enfin, ce serait génial si nous pouvions tout de suite aller à la page ''character_detail'' avec le contenu que nous venons de créer. Pour cela, nous avons besoin d'importer une dernière chose :
+
+
Maintenant, nous allons ajouter la ligne qui signifie "aller à la page ''character_detail'' pour le changement qui vient d'être enregistré.
<p>Voyons si ça marche. Allez à l'adresse <a href="http://127.0.0.1:8000/character/Tic/" target="_blank">http://127.0.0.1:8000/character/Tic/</a>, selectionnez un nouveau lieu, sauvegardez ... et voilà ! La mise a jour est prise en compte !</p>
+
Voyons si ça marche. Allez à l'adresse ''http://127.0.0.1:8000/character/Tic/'', selectionnez un nouveau lieu, sauvegardez ... et voilà ! La mise a jour est prise en compte !
-
</html>
+
==== Modèle complet ====
==== Modèle complet ====
Ligne 306:
Ligne 311:
</code>
</code>
-
==== Encore un petit effort : déployons ! ====
-
<html>
-
<p>Nos modifications fonctionnent-elles sur PythonAnywhere ? Pour le savoir, déployons à nouveau !</p>
-
<ul>
-
<li>Tout d'abord, commitez votre nouveau code et pushez le à nouveau sur GitHub:</li>
$ git commit -m "Added views to create/edit blog post inside the site."
-
$ git pus
-
</code></pre><ul>
-
<li>Puis, dans la console bash de <a href="https://www.pythonanywhere.com/consoles/" target="_blank">PythonAnywhere</a>:</li>
-
</ul>
-
<p></p><p class="code-label">Ligne de commande PythonAnywhere</p><p></p>
-
<pre><code>$ cd ~/<your-pythonanywhere-domain>.pythonanywhere.com
-
$ git pull
-
[...]
-
</code></pre><p>(N’oubliez pas de remplacer <code><your-pythonanywhere-domain></code> avec votre propre sous-domaine PythonAnywhere, sans les chevrons.)</p>
-
<ul>
-
<li>Enfin, allez sur <a href="https://www.pythonanywhere.com/web_app_setup/" target="_blank">"Web" page</a> (utilisez le bouton de menu en haut à droite de la console) et cliquez <strong>Reload</strong>. Actualisez votre blog <a href="https://subdomain.pythonanywhere.com" target="_blank">https://subdomain.pythonanywhere.com</a> pour voir les changements.</li>
-
</ul>
-
<p>Et normalement c'est tout ! Félicitations ! :)</p>