Django : les vues et le templating

On continue avec les vues, pour rester dans la cadre du tuto de la doc. Entre temps, j’ai continué de me documenter sur Django. Le doute que j’avais sur le contenu et la taille des modèles se confirme. En regardant ce que les autres faisaient sur Pypi (le packagisst pour Python) il se trouve que les app contiennent bien un seul fichier models.py, avec des centaines de lignes dedans. On va voir plus bas que pour les vues, c’est pareil !

challenge python

Les controlleurs qui s’appellent des vues

Alors ouvrons le fichier views.py, qui va gérer toutes les vues de l’app :

def detail(request, question_id):
    return HttpResponse("ici c'est la question %s. " % question_id)


def results(request, question_id):
    response = "Et là c'est la question %s."
    return HttpResponse(response % question_id)


def vote(request, question_id):
    return HttpResponse("Tu votes sur la question %s." % question_id)

Je ne connaissais pas cette syntaxe avec PHP pour chainer les choses, mais ce qui me choque le plus, c’est que c’est la vue qui gère la partie HTTP. Pour moi ça n’a rien à faire là, c’est peut-être juste pour l’exemple, et la gestion des controllers sera probablement pour un autre chapitre.

Ensuite il faut aller ajouter ces méthodes dans le fichier urls.py de l’application pools.

urlpatterns = [
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

On dirait que chez les Pythonneurs, on aime beaucoup la regex. Encore une fois, je suis un peu étonné de voir pointer une url directement sur une vue. On verra pour la suite, mais il semble vraiment que les « views » soient en fait des controllers.
On a déjà vu la gestion des urls dans un autre billet, on va passer les détails ici. Il faut juste garder à l’esprit que vu qu’on a chargé le fichier pools/urls.py depuis le fichier d’url du projet comme ceci : url(r’^polls/’, include(‘polls.urls’)), toutes les urls sont préfixées par /pools/****

Avec un peu de données sorties de la bdd

On va réécrire la méthode index comme suit, pour sortir des données, et faire autre chose qu’un hello world de base :

def index(request):
    last_questions = Question.objects.order_by('-pub_date')[:5]
    data = ' , ' .join([q.question_text for q in last_questions])
    return HttpResponse(data)

C’est aussi un nouveau concept d’avoir accès à des fonctions qui commencent par un point. Je pousserai la question plus tard. En plus, cette nouvelle façon de faire un for est plutôt intéressante.

Le templating

Bon cette confusion vue/controlleur se confirme. Vous me direz, ça va avec le titre du billet, mais ce n’était pas volontaire. Donc ce que j’appelais les vues dans mes projets web, correspondend aux templates dans Django.

Pour la faire courte, pour Python, la vue décrit quel type de donnée tu vois, pas comment tu la vois. Du coup Django parle de MTV (non, pas la chaine TV). Plus de détails

Donc par défaut, il faut créer un dossier templates dans chaque dossier d’application. Dans notre exemple, polls/templates. C’est là qu’on va pouvoir déposer des fichiers avec une extension .html.

On va donc créer polls/tempaltes/index.html :

{% if latest_question %}

<ul>
    {% for question in latest_question %}

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

    {% endfor %}
    </ul>

{% else %}


Aucun sondage disponible.

{% endif %}

Et il faut ensuite dire à la vue (le controller, histoire de faire la transition ^^⁾, et importer le loader de template, puis modifier la méthode index pour utiliser le fichier :

from django.template import loader


def index(request):
    last_questions = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/templates/inidex.html')
    context = {'last_questions': last_questions}
    #il existe un raccouci pour cette façon de rendre, voici les 2 méthodes: 
    return HttpResponse(template.render(context, request))
    return render(request, 'polls/index.html', context)

La méthode render() prend en paramètre l’objet request : je n’ai pas encore compris pourquoi. Visiblement ça permet par exemple de déterminer si un user est connecté par exemple. Ce que je ferai aussi sans la requête sur un Laravel par exemple.

En plus je trouve que rendre ce type de paramètre obligatoire (le premier !) est plutôt dommage. Ca pourrait par exemple être le travail de la méthode render() de l’injecter elle-même.
En second paramètre, le chemin vers le template : Encore une fois, par exemple, il fait préciser polls/index.html. Ca serait à mon sens plus simple de partir du dossier polls/templates/ directement, et écrire uniquement index (vu que visiblement, le moteur de template dans Django veut des fichiers .html).
En 3e paramètre, on colle les données à transmettre au template : dans notre exemple, le dictionnaire d’objets Question.

Le moteur de template attend des {{ question.question_text }} quand on veut afficher des variables, et des {% if %} quand on veut utiliser les fonctions du langage (if, for, etc).

Nommer les routes

Il est possible, comme dans n’importe quel Framework web, de donner des noms à ses routes. Si on reprend notre exemple :

from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

Le détail important c’est qui va ajouter un préfixe sur toutes les urls déclarées ensuite. Il y a aussi le paramètre name en dernier paramètre de chaque déclaration.
Donc si on veut utiliser une route par son nom :


<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

#ou alors, si on doit changer de namespace (notre namespace actuel est par exemple polls

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

SY

Recherches utilisées pour trouver cet article :je pousserai les chaînes comme django
metrogeek

Comments 1

Laisser un commentaire