TP : Gestion d’une liste de tâches - Views et URLs (3/3)¶
date: | 2012-04-30 16:34 |
---|---|
tags: | django, python |
category: | Django |
author: | Rémy Hubscher |
Récapitulatif¶
Nous avons vu dans le chapitre précédent comment créer les views et afficher notre liste de tâches.
Je vous rappelle que, dans un premier temps, nous avons une unique liste :
- Nous voulons ajouter des tâches dans la liste
- Nous voulons pouvoir vider la liste en fin de journée
- Nous voulons dire que la tâche est réalisée (la barrer)
- Nous voulons pouvoir marquer toutes les tâches comme terminée
- Nous voulons pouvoir supprimer une tâche
Nous allons maintenant en faire en sorte de pouvoir ajouter une tâche.
Ajouter une tâche¶
Nous allons mettre en place un form pour éditer notre modèle.
Créer un fichier forms.py et y ajouter ces informations.
forms.py
# -*- coding: utf-8 -*-
from django import forms
from todo.models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
exclude = ('is_resolved',)
On va ensuite gérer ce formulaire dans une nouvelle vue
views.py
# -*- coding: utf-8 -*-
# [...] On rajoute au document le code suivant
from django.views.generic import ListView, CreateView
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect
from todo.forms import TaskForm
class TaskCreateView(CreateView):
form_class = TaskForm
success_url = reverse_lazy('tasks-list')
def form_invalid(self, form):
# Attention les erreurs du form ne seront pas affichées
return HttpResponseRedirect(self.success_url)
Pour l’instant la seule erreur c’est que le champ soit vide. Dans notre cas, la tâche ne sera pas sauvegardée si on renvoit un content vide.
urls.py
On commence à avoir plusieurs urls pour notre module todo. Comme on souhaite qu’il soit réutilisable, on va mettre toutes les urls concernant les todos dans le fichier todo/urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from todo.views import *
urlpatterns = patterns('',
url(r'^$', TasksView.as_view(), name='tasks-list'),
url(r'^add/$', TaskCreateView.as_view(), name='task-create'),
)
Dans le fichier url de notre projet tuto_django/urls.py, on va inclure les urls des todo
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from django.views.generic import RedirectView
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', RedirectView.as_view(url='todo/')),
url(r'^admin/', include(admin.site.urls)),
url(r'^todo/', include('todo.urls')),
)
On demande aussi de rediriger notre page d’accueil vers todo/
tasks-list.html
<header id="header">
<h1>{% trans 'Todos' %}</h1>
<form action="{% url task-create %}" method="post">
{% csrf_token %}
<input id="new-todo" placeholder="{% trans 'What needs to be done?' %}" name="content" autofocus>
</form>
</header>
Le csrf_token est une sécurité de Django pour éviter qu’un script maveillant envoi notre formulaire sans le charger au préalable.
Le navigateur sait que lorsqu’on appuie sur ENTER il doit envoyer le formulaire.
Nous pouvons maintenant ajouter des tâches.
Supprimer les tâches terminées¶
views.py
TASK_LIST_URL = reverse_lazy('tasks-list')
def clear_resolved_tasks(request):
if request.method == 'POST':
# Modify an object in POST only
Task.objects.filter(is_resolved=True).delete()
return HttpResponseRedirect(TASK_LIST_URL)
Une toute petite fonction qui va récupérer les tâches terminées et les supprimer. On vérifie juste que la fonction a bien été appelé en POST car on modifie des données.
urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from todo.views import *
urlpatterns = patterns('',
url(r'^$', TasksView.as_view(), name='tasks-list'),
url(r'^clear/$', clear_resolved_tasks, name='tasks-clear'),
url(r'^add/$', TaskCreateView.as_view(), name='task-create'),
)
tasks-list.html
<footer id="footer">
<form action="{% url tasks-clear %}" method="post">
{% csrf_token %}
<button id="clear-completed" onclick="this.parentNode.submit();">{% trans 'Clear completed' %}</button>
</form>
</footer>
Marquer une tâche comme terminée¶
views.py
from django.shortcuts import get_object_or_404
def toggle_task(request, task_id):
if request.method == 'POST':
# Modify an object in POST only
task = get_object_or_404(Task, pk=task_id)
task.is_resolved = not task.is_resolved
task.save()
return HttpResponseRedirect(TASK_LIST_URL)
urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from todo.views import *
urlpatterns = patterns('',
url(r'^$', TasksView.as_view(), name='tasks-list'),
url(r'^clear/$', clear_resolved_tasks, name='tasks-clear'),
url(r'^add/$', TaskCreateView.as_view(), name='task-create'),
url(r'^toggle/(?P<task_id>\d+)/$', toggle_task, name='task-toggle'),
)
tasks-list.html
<form method="post" action="{% url task-toggle task.id %}">
{% csrf_token %}
<input class="toggle" type="checkbox"{% if task.is_resolved %} checked="checked"{% endif %} onclick="this.parentNode.submit();">
</form>
Marquer toutes les tâches comme terminées¶
views.py
def toggle_tasks(request):
if request.method == 'POST':
# Modify an object in POST only
try:
task = Task.objects.all()[0]
except IndexError:
task = None
if task is not None:
status = not task.is_resolved
Task.objects.all().update(is_resolved=status)
return HttpResponseRedirect(TASK_LIST_URL)
urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from todo.views import *
urlpatterns = patterns('',
url(r'^$', TasksView.as_view(), name='tasks-list'),
url(r'^clear/$', clear_resolved_tasks, name='tasks-clear'),
url(r'^toggle/$', toggle_tasks, name='tasks-toggle'),
url(r'^add/$', TaskCreateView.as_view(), name='task-create'),
url(r'^toggle/(?P<task_id>\d+)/$', toggle_task, name='task-toggle'),
)
tasks-list.html
<form method="post" action="{% url tasks-toggle %}">
{% csrf_token %}
<input id="toggle-all" type="checkbox" onclick="this.parentNode.submit();">
</form>
Supprimer une tâche¶
views.py
from django.views.generic import ListView, CreateView, DeleteView
class TaskDeleteView(DeleteView):
model = Task
success_url = TASK_LIST_URL
urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from todo.views import *
urlpatterns = patterns('',
url(r'^$', TasksView.as_view(), name='tasks-list'),
url(r'^clear/$', clear_resolved_tasks, name='tasks-clear'),
url(r'^toggle/$', toggle_tasks, name='tasks-toggle'),
url(r'^add/$', TaskCreateView.as_view(), name='task-create'),
url(r'^toggle/(?P<task_id>\d+)/$', toggle_task, name='task-toggle'),
url(r'^delete/(?P<pk>\d+)/$', TaskDeleteView.as_view(), name='task-delete'),
)
tasks-list.html
<form method="post" action="{% url task-delete task.id %}">
{% csrf_token %}
<button class="destroy" onclick="this.parentNode.submit();"></button>
</form>
Conclusion¶
C’est extrèmement simple de faire une application web avec Django, la plupart des briques sont là et il ne reste plus qu’à les utiliser.
Le code complet est disponible ici : http://bitbucket.org/natim/django-story/src/tip/demos/tuto_django
Vous pouvez tester cette application ici : http://django-story.ionyse.com/demos/todo/