> Modules non standards > Django pour le développement web > Les views génériques
Les views génériques
Generic views :
- l'objectif est d'écrire le moins possible de code pour des choses répétitives.
- ce sont des views basées sur des classes héritant de la classe View, plutôt que des simples fonctions.
- intérêt d'utiliser des classes : avant, il y avait des fonctions views génériques avec beaucoup d'arguments pour modifier leur comportement, c'était très lourd. Maintenant, il suffit d'hériter d'une classe et de surcharger seulement les attributs et méthodes à modifier. Beaucoup plus simpl et propre !
Principales vues génériques :
- TemplateView, pour la présentation d'un template.
- RedirectView, pour un redirect.
- DetailView, pour la présentation d'un objet.
- ListView, pour la présentation d'une liste d'objets.
- FormView, pour une form quelconque.
- CreateView, pour la création d'un objet.
- UpdateView, pour la modification d'un objet.
- DeleteView, pour la destruction d'un objet.
View
Toutes les classes View en héritent indirectement.
View définit une méthode dispatch() qui est appelée pour le traitement de la requête et doit renvoyer une response :
class MyView(...)
def dispatch(self, *args, **kwargs):
# args contient les paramètres comme GET, POST, COOKIES
# et META : dictionnaire qui contient SERVER_NAME, SERVER_PORT, CONTENT_TYPE, HTTP_HOST, etc ...
* kwargs est un dictionnaire avec les paramètres nommés spécifiques de la requête (ceux du get ou du post).
return super(MyView, self).dispatch(*args, **kwargs)
TemplateView
TemplateView :
- classe générique dont on hérite pour présenter simplement un template.
- exemple : dans le fichier urls.py, on indique la classe en appelant la méthode as_view() qui renvoie une fonction view :
url('^help(?:/(?P<var>.*))', HelpView.as_view(), name = 'helpPage')
et dans le fichier views.py, on définit la classe qui hérite de TemplateView, en indiquant le template à utiliser :
from django.views.generic import TemplateView
class HelpView(TemplateView):
template_name = 'help.html'
et enfin, dans le template, on peut utiliser la variable {{ var }}.
- si la seule chose que fait la sous-classe est de redéfinir des variables de classe, on peut simplement faire dans urls.py : url('^help(?:/(?P<var>.*))', TemplateView.as_view(template_name = 'help.html'), name = 'helpPage')
- on récupére aussi des variables passées dans un dictionnaire lors de la définition de l'url :
url('^help(?:/(?P<var>.*))', HelpView.as_view(), {'var2': 'voiture'}, name = 'helpPage')
- on peut aussi rajouter des variables dans la vue en surchargeant la méthode get_context_data :
class HelpView(TemplateView):
template_name = 'help.html'
def get_context_data(self, **args):
context = super(HelpView, self).get_context_data(**args)
# on rajoute ici une nouvelle variable au contexte
context['var3'] = 'pomme'
return context
RedirectView
RedirectView :
- classe générique dont on hérite pour rediriger vers une url.
- exemple : dans le fichier urls.py, on donne :
url(r'^help2/(?P<valeur>\w+)?$', views.HelpView2.as_view(), name = 'helpPage2')
et dans le fichier views.py, on définit la classe qui hérite de RedirectView, en indiquant l'url à utiliser, ici, rediriger vers l'url dont le nom est helpPage :
from django.views.generic import RedirectView
class HelpView2(RedirectView):
pattern_name = 'helpPage'
permanent = False
- bien sûr, comme dans tout redirect, l'url va changer dans le navigateur pour afficher la nouvelle url.
- permanent = False : indique que la redirection n'est pas permanente (statut 302). Par défaut, permanent vaut True (statut 301) : une fois qu'il y a eu redirection, la prochaine requête avec la même url ira directement vers l'url finale (c'est la bonne redirection à faire quand on veut changer l'adresse d'une ressource).
- au lieu de donner un nom d'url sur lequel un reverse doit être fait, on peut donner directement : url = '/myUrl/' et si url est défini, il prend le pas sur pattern_name.
- au lieu de donner une url, on peut surcharger le méthode get_redirect_url() qui prend args et kwargs (les 2 arguments) en les remplissant en fonction du type d'url (par position ou par nom) :
class HelpView2(RedirectView):
def get_redirect_url(self, *args, **kwargs):
...
return reverse('helpPage', kwargs = myDict)
par défaut, cette méthode renvoit url si défini, et sinon fait un reverse sur pattern_name.
DetailView
DetailView :
- classe générique dont on hérite pour présenter un seul objet d'une table de la base de données.
- exemple :
from django.views.generic import DetailView
class MyView(DetailView):
model = MyModel
et dans urls.py : url(r'^show/(?P<pk>\d+)/$', MyView.as_view())
- champs que l'on peut ajouter :
- content_type : le content-type de la réponse (par exemple text/html)
- template_name = 'myApp/myTemplate.html : si on ne précise pas le template, il cherche un template myApp/mymodel_detail.html (avec le nom de la classe modèle en minuscules).
- context_object_name = 'obj' : le nom de la variable à utiliser dans le template pour représenter l'objet (sinon, c'est mymodel, le nom de la classe en minuscules).
- slug_field = 'id' : le nom du champ clef primaire de l'objet MyModel (c'est 'id' par défaut).
- slug_url_kwarg = 'pkName' : le nom du champ dans l'url. Par défaut, c'est pk qui est recherché.
- pour accéder à l'instance de l'objet à afficher : self.object.
- on peut surcharger get_context_data pour rajouter des variables utilisables dans le template :
class MyView(DetailView):
model = MyModel
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['title'] = 'mon titre'
return context
- on peut surcharger la méthode get_object() qui doit renvoyer l'objet à afficher (et qui est stocké dans self.object).
- on peut surcharger la méthode get_template_names() pour renvoyer le template que l'on veut (par défaut, c'est la valeur de template_name qui est renvoyée).
- on peut surcharger la méthode get_slug_field() pour renvoyer la valeur du slug_field ci-dessus, si celle-ci n'est pas une constante.
- on peut surcharger la méthode get_context_object_name() pour renvoyer la valeur de context_object_name si celle-ci n'est pas une constante.
- on peut surcharger la méthode render_to_response(context) pour renvoyer la réponse.
ListView
ListView :
- classe générique dont on hérite pour présenter une liste d'objet d'une table de la base de données.
- exemple :
from django.views.generic import ListView
class MyView(ListView):
model = MyModel
queryset = MyModel.objects.all().order_by('label')
et dans urls.py : url(r'^list/$', views.MyView.as_view()).
- champs que l'on peut ajouter :
- content_type : le content-type de la réponse (par exemple text/html)
- template_name = 'myApp/myTemplate.html' : si l'on ne précise pas le template, il cherche un template myApp/mymodel_list.html (avec le nom de la classe modèle en minuscules).
- context_object_name = 'obj' : le nom de la variable à utiliser dans le template pour représenter l'objet (sinon, c'est mymodel, le nom de la classe en minuscules).
- pour accéder à l'instance de l'objet à afficher : self.object_list.
- on peut surcharger get_context_data pour rajouter des variables utilisables dans le template :
class MyView(ListView):
model = MyModel
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['title'] = 'mon titre'
return context
- on peut surcharger la méthode get_queryset() qui doit renvoyer le query set quand on veut qu'il soit dynamique.
- on peut surcharger la méthode get_template_names() pour renvoyer le template que l'on veut (par défaut, c'est la valeur de template_name qui est renvoyée).
- on peut surcharger la méthode get_context_object_name() pour renvoyer la valeur de context_object_name si celle-ci n'est pas une constante.
- on peut surcharger la méthode render_to_response(context) pour renvoyer la réponse.
FormView
FormView :
- la classe générique dont on hérite pour présenter un formulaire quelconque : elle permet d'utiliser une classe dérivée de Form directement.
- exemple : la classe ci-dessous sert à la fois à présenter la form (méthode form_valid n'est pas appelée) et à la soumettre par exemple pour faire une requête et renvoyer des résultats (méthode form_valid appelée si les données sont valides) :
from django.views.generic import FormView
class MyView(FormView):
template_name = 'myTemplate.html'
form_class = MyForm
def form_valid(self, form):
# On fait ici la requete pour avoir une liste d'objets
...
myObjList = list(myQuerySet)
return render(self.request, 'myTemplate.html', {'myObjList': myObjList})
avec la form :
class MyForm(Form):
label = CharField(label = 'Label', max_length = 5, required = False)
description = CharField(label = 'Description', max_length = 100, required = False)
et dans urls.py : url(r'^myUrl/$', MyView.as_view())
- champs que l'on peut ajouter :
- content_type : le content-type de la réponse (par exemple text/html)
- template_name : le template à présenter quand on présente la forme.
- success_url : url vers laquelle rediriger après que la form ait été soumise si c'est une url fixe.
- initial = {'label': 'A*', 'description': 'd*'} : les valeurs qu'ils font mettre dans les champs initialement.
- dans la méthode form_valid(self, form) qui est appelée si la form soumise est valide, on peut récuperer les données de la form grâce au dictionnaire form.cleaned_data. Pour chaque champ, la valeur vaut None si le champ n'est pas rempli.
- on peut surcharger get_context_data pour rajouter des variables utilisables dans le template :
class MyView(ListView):
model = MyModel
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['title'] = 'mon titre'
return context
CreateView
CreateView :
- classe générique dont on hérite pour créer un objet dans une table de la base de données.
- exemple :
from django.views.generic import CreateView
class MyView(CreateView):
model = MyModel
fields = ['label', 'description']
et dans urls.py : url(r'^create/$', MyView.as_view()) et dans le modèle, une fonction qui renvoie l'adresse de redirection juste après création de l'objet :
class MyModel(models.Model):
def get_absolute_url(self):
return reverse('myUrl', kwargs = {'pk': self.pk})
- la classe s'occupe toute seule de créer l'objet et de le sauver dans la base de données.
- alternativement, plutôt que de définir une fonction get_absolute_url dans le modèle, on peut définir get_success_url dans la classe view :
class MyView(CreateView):
def get_success_url(self):
return reverse('myUrl', kwargs = {'pk': self.object.pk})
- champs que l'on peut ajouter :
- template_name = 'myApp/myTemplate.html' : si l'on ne précise pas le template, il cherche un template myApp/mymodel_form.html (avec le nom de la classe modèle en minuscules).
- on peut surcharger get_context_data pour rajouter des variables utilisables dans le template :
class MyView(CreateView):
model = MyModel
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['title'] = 'mon titre'
return context
- pour modifier certains champs avant qu'ils ne soient sauvés dans la base, la fonction form_valid est appelée si les données de la forme sont valides :
class MyView(CreateView):
def form_valid(self, form):
form.instance.label += '0' # add a 0 at the end of the label field of the model
return super(MyView, self).form_valid(form)
- on peut customiser la form en utilisant un ModelForm et en l'indiquant dans la View :
class MyView(CreateView):
model = MyMode
fields = ['label', 'description']
template_name = 'myApp/mymodel_form.html'
form_class = MyForm
et
class MyForm(ModelForm):
label = CharField(label = 'Label', max_length = 5, \
validators = [validateLabel], widget = TextInput(attrs = {'size': 5}))
class Meta:
model = MyModel
UpdateView
UpdateView :
- classe générique dont on hérite pour modifier un objet dans une table de la base de données.
- la classe sert à la fois à présenter le formulaire de mise à jour et à faire la mise à jour.
- exemple :
from django.views.generic import UpdateView
class MyView(UpdateView):
model = MyModel
template_name = myTemplate.html
form_class = MyModelForm
success_url = '/bravo'
et dans urls.py : url(r'^update/(?P<pk>\d+)/$', MyView.as_view()).
- on peut rajouter une méthode get_success_url dans la classe qui indique vers quelle adresse on doit rediriger après l'update :
class MyView(UpdateView):
model = MyModel
template_name = myTemplate.html'
form_class = MyModelForm
def get_success_url(self):
return reverse('myUrl', kwargs = {'pk': self.pk})
- champs que l'on peut ajouter :
- slug_field = 'id' : le nom du champ clef primaire de l'objet MyModel (c'est 'id' par défaut).
- slug_url_kwarg = 'pkName' : le nom du champ dans l'url. Par défaut, c'est pk qui est recherché.
DeleteView
Copyright python-simple.com
programmer en python, tutoriel python, graphes en python, Aymeric Duclert