[PYTHON] Prise en main et utilisation d'exemples de vues génériques basées sur des classes dans Django

Si vous avez des erreurs ou des malentendus, veuillez les signaler.

Pourquoi écrire cet article

Django a un langage de template puissant.

C'est la vue qui fournit les données au modèle. Et il existe également un moyen rapide de le coder. C'est la "vue générique".

Il semble que nous utilisions il y a longtemps des vues génériques basées sur des fonctions, mais maintenant nous utilisons principalement des vues basées sur des classes. La traduction japonaise actuelle de Django est 1.4, mais il existe un document de vue générique basé sur les classes.

http://docs.djangoproject.jp/en/latest/topics/class-based-views.html

Cependant, il y avait moins d'articles expliquant les vues générales basées sur la classe que je ne le pensais, j'ai donc décidé de les écrire.

Contenu de cet article

Qu'est-ce qu'une vue générique

La vue est le contrôleur dans Rails. Django semble l'appeler vue car elle est basée sur l'idée de MTV (Model, Template, View).

Il est responsable de fournir les données au modèle, mais la plupart des sites Web

--Liste des conditions spécifiques

Il a une fonction appelée. Le processus est défini à l'avance dans Django afin que vous n'ayez pas à écrire plusieurs fois du code similaire.

Elles sont appelées "vues à usage général", et si elles sont fournies par une fonction, elles sont appelées "vues à usage général basées sur une fonction", et si elles sont fournies par une classe, elles sont appelées "vues à usage général basées sur une classe".

Dans la vue générale, la valeur par défaut appropriée est définie en fonction du modèle, du formulaire, etc. Par conséquent, il présente l'avantage que le montant écrit par le programmeur est très faible.

Cet article décrit les «vues génériques basées sur les classes».

Les vues génériques basées sur les classes définissent un traitement similaire pour chaque classe. Nous pouvons hériter de cette classe, modifier les variables de classe si nécessaire et remplacer les méthodes pour insérer notre propre traitement.

Comment utiliser la vue générique basée sur les classes

Premier pas

** C'est la première étape, alors concentrons-nous sur la façon de l'écrire. ** **

Les vues génériques sont principalement utilisées dans views.py etc. Liez également l'URL avec la fonction ʻas_view () dans ʻurls.py.

Écrivons un échantillon. Supposons que vous ayez créé un projet avec django-admin etc. et créé une application en tant que manager.py startapp foo.

Eh bien, je vais écrire.

foo/views.py


from django.views.generic import TemplateView

class SampleTemplateView(TemplateView):
    template_name = "index.html"

Il est maintenant prêt à être utilisé. Vous pouvez voir que la quantité de description est très faible.

Ici, «TemplateView» est une vue générique. Les vues sont préparées pour chaque objectif dans django.views.generic etc., donc ʻimport` et héritent.

L'URL est

urls.py


from foo.views import SampleTemplateView

urlpatterns = [
    url(r'^sample$', SampleTemplateView.as_view()),
]

Si tel est le cas, SampleTemplateView le gérera bien lors de l'accès à / sample.

De cette façon, vous pouvez réduire considérablement la quantité de code que vous écrivez dans views.py. Comme son nom l'indique, «TemplateView» est destiné à être dessiné à l'aide d'un modèle. Si vous utilisez une autre vue à usage général au lieu de TemplateView, vous pouvez afficher la liste sans écrire le code pour obtenir les données de la base de données, ou vous pouvez sortir les données après avoir réduit par des conditions spécifiques.

Je veux transmettre les variables que j'ai définies au modèle

Dans la première étape, je ne pouvais afficher que le modèle. Cependant, vous souhaiterez généralement afficher les données lues dans la base de données.

Dans ce cas, remplacez la méthode définie dans la vue générique.

La méthode que je remplace souvent est «get_context_data».

Utilisez-le comme suit.

views.py


from django.views.generic import TemplateView


class SampleTemplate(TemplateView):

    template_name = "index.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs) #Appelez d'abord la méthode héritée
        context["foo"] = "bar"
        return context

Utilisez comme.

Dans le code ci-dessus, le modèle vous permet d'utiliser une variable appelée foo. Si vous utilisez {{foo}} dans le modèle, ce sera bar.

Si le nom de fichier du modèle est ʻindex.html` etc.

index.html


<div class="sample">{{ foo }}</div>

étant donné que,

index.html


<div class="sample">bar</div>

Cela signifie que.

En d'autres termes, si vous décrivez le processus que vous souhaitez insérer dans cette méthode et le mettez dans la valeur de retour de get_context_data, vous pouvez l'utiliser dans le modèle.

Résumé de ce chapitre

De cette manière, vous pouvez remplacer la méthode dans la vue générale et ajouter le traitement dont vous avez besoin. Ceci est l'utilisation de base.

Il existe de nombreuses vues à usage général utiles telles que «ListView» pour afficher une liste et «DetailView» pour créer des pages individuelles, je vais donc les présenter.

Types de vues génériques basés sur les classes (partiels)

** Remarque: tous ne sont pas présentés ici **

https://github.com/django/django/blob/master/django/views/generic/init.py

Si vous regardez, beaucoup plus de vues génériques sont définies, telles que «RedirectView» et «FormView».

TemplateView

Comme son nom l'indique, TemplateView est une vue à usage général qui affiche quelque chose en spécifiant un modèle. Par conséquent, le nom du modèle doit être spécifié.

Il appelle également get_context_data, donc il remplace et définit les données requises. Bien sûr, il est hors du contrôle de la vue générale, vous devez donc faire le comptage et le filtrage vous-même.

views.py


from django.views.generic import TemplateView


class MyTemplateView(TemplateView):

    template_name = "index.html"  #Obligatoire

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        #Faire diverses choses
        return context

L'auteur l'utilise principalement sur la première page du site.

ListView

https://docs.djangoproject.com/ja/1.9/ref/class-based-views/generic-display/#listview

Comme son nom l'indique, «ListView» est utilisé lors de la création de pages de liste.

Si vous créez simplement une liste de modèles cibles,

views.py


from django.views.generic import ListView
from foo.model import MyModel

class MyListView(ListView):

    model = MyModel

Il est défini comme. model = MyModel est le modèle qui crée la liste.

Le modèle ressemblerait à ceci.

mymodel/mymodel_list.html


<ul>
  {% for item in object_list %}
  <li>{{ item }}</li>
  {% endfor %}
</ul>

Même s'il y a beaucoup de données dans la base de données, ListView divisera la liste par 10 par défaut </ s> (modifié comme indiqué dans le commentaire), mais tous les éléments seront acquis, mais les variables décrites plus loin Vous pouvez contrôler le nombre d'éléments sortis sur une page avec. Le nombre à diviser est une variable appelée paginate_by.

En d'autres termes, si vous souhaitez diviser 5 cas à la fois

views.py


class MyListView(ListView):
    model = MyModel
    paginate_by = 5

Est défini comme.

Il s'agit d'un paramètre selon lequel s'il y a 100 données, seules 5 seront affichées sur une page.

De plus, vous souhaiterez parfois modifier l’ordre de tri des données à acquérir à l’avance ou les filtrer et les contrôler. Dans ce cas, remplacez la méthode get_queryset.

views.py


class MyListView(ListView):
    model = MyModel
    paginate_by = 5

    def get_queryset(self):
        return MyModel.objects.filter(some_column=foo)

Faire. Ensuite, il émettra la requête définie par get_queryset et stockera les données dans ʻobject_list`.

Si vous souhaitez limiter le nombre d'éléments à extraire dans la liste, spécifiez ici.

La désignation est une tranche normale.

views.py



def get_queryset(self, queryset=None):
    return MyModel.objects.all()[:10]

Avec cela, même s'il y a 100 éléments de données, seuls 10 éléments seront extraits.

Cette écriture peut être un peu plus courte.

views.py


class MyListView(ListView):
    model = MyModel
    paginate_by = 5
    queryset = MyModel.objects.filter(some_column=foo)

Quelle que soit votre utilisation, le résultat ne changera pas.

Si vous souhaitez émettre des requêtes de manière dynamique, utilisez le premier, et si vous voulez toujours le même résultat, utilisez le second.

Bien sûr, vous pouvez transmettre des données d'autres tables au modèle en remplaçant la méthode get_context_data.

views.py


class MyListView(ListView):
    model = MyModel
    paginate_by = 5

    def get_queryset(self):
        return MyModel.objects.filter(some_column=foo)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**data)
        context["bar"] = OtherModel.objects.all()  #Obtenez des données d'autres modèles
        return context

Cependant, dans ce cas, ʻOtherModel n'est pas sous le contrôle de la vue générique, donc context ["bar"] stocke le nombre entier de ʻOtherModel.

DetailView

https://docs.djangoproject.com/ja/1.9/ref/class-based-views/generic-display/#detailview

Comme son nom l'indique, «DetailView» est une vue à usage général pour les pages de détails individuelles. Acquiert des données pour une seule ligne d'enregistrements.

views.py



from django.views.generic import DetailView
from mymodel.model import MyModel


class MyDetailView(DetailView):
    model = MyModel

L'URL est

urls.py


urlpatterns = [
    url(r'^(?P<pk>\d+)$', MyDetailView.as_view()),
]

ça ira. pk est la clé primaire, mais DetailView utilise ce nom pour identifier l'enregistrement. Vous pouvez le changer, mais si vous n'en avez pas besoin, vous pouvez le laisser tel quel.

CreateView / UpdateView

https://docs.djangoproject.com/ja/1.9/ref/class-based-views/generic-editing/#django.views.generic.edit.CreateView

CreateView est une vue qui fournit un formulaire pour ajouter un nouvel enregistrement. ʻUpdateView` est, comme vous pouvez vous y attendre, une vue qui fournit un formulaire pour mettre à jour les données existantes.

views.py


from django.views.generic.edit import CreateView

class MyCreateView(CreateView):
    model = MyModel
    fields = ("name", )  #Liste ou taple

Définissez-le comme ça. Ce n'est pas très différent des autres vues génériques. Cependant, vous devez définir une variable appelée «fields» dans «CreateView» et «UpdateView ». Cela signifie que lorsque des données sont saisies à partir du formulaire, elles seront ignorées sauf pour les champs définis dans les champs. Est-ce quelque chose comme des paramètres forts dans les rails?

Ce qui distingue CreateView et ʻUpdateViewdes autres vues génériques, c'est qu'elles" créent un formulaire ". Autrement dit, il crée une variable appeléeform au lieu de ʻobject ou ʻobject_list`.

La variable form contient des données pour créer un formulaire, ce qui facilite la création d'un formulaire.

Voici un modèle qui utilise la variable form.

<form method="post">
    {% csrf_token %}
    <table>
        {{ form }}
    </table>
    <input type="submit">
</form>

Vous devez écrire vous-même la balise HTML «

</ form>», mais les champs du formulaire seront générés pour vous. Par défaut, {{form}} affiche les champs en utilisant des tables. Si vous voulez créer un champ en utilisant la balise <p> </ p>, utilisez {{form.as_p}}.

{% csrf_token%} est une mesure CSRF. Requis si vous avez créé un formulaire POST, etc. avec Django.

https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA

http://docs.djangoproject.jp/en/latest/ref/contrib/csrf.html

Vous pouvez également utiliser des objets de formulaire tels que «ModelForm».

De cette manière, vous pouvez facilement exploiter vos classes de formulaire existantes.

forms.py


from django import forms
from myapp.model import MyModel

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ("name", )

views.py


from forms import MyModelForm

class MyCreateView(CreateView):
    form_class = MyModelForm

La validation est également une caractéristique importante de ces formulaires. Même si vous soumettez le formulaire avec beaucoup d'efforts, si une erreur se produit lors de la validation et qu'il n'est pas ajouté ou mis à jour, cela peut être déroutant si vous n'en informez pas l'utilisateur.

Par conséquent, les méthodes form_valid et form_invalid sont définies dans ces vues générales et vous pouvez effectuer le traitement nécessaire selon que la validation a réussi ou non.

Par exemple, nous disons souvent aux utilisateurs si le formulaire qu'ils ont soumis a été enregistré avec succès. A cette époque, Django utilise le framework de messages.

http://docs.djangoproject.jp/en/latest/ref/contrib/messages.html

views.py


from django.views.generic.edit import CreateView
from django.contrib import messages  #Cadre de message

from myapp.models import MyModel


class MyCreateView(CreateView):
    model = MyModel

    def form_valid(self, form):
        '''Une fois la validation réussie'''
        messages.success(self.request, "Enregistré")
        return super().form_valid(form)

    def form_invalid(self, form):
        '''Lorsque la validation échoue'''
        message.warning(self.request, "Impossible d'enregistrer")
        return super().form_invalid(form)

Ici, nous avons ajouté nos propres messages à la méthode form_valid, qui est appelée lorsque la validation est réussie, et à form_invalid, qui est appelée lorsque la validation échoue.

En faisant cela, vous pouvez ajouter votre propre traitement, donc en plus de l'exemple ci-dessus, vous pouvez insérer un traitement tel que notifier l'administrateur par e-mail lorsqu'une erreur se produit.

Lorsque vous avez terminé votre propre traitement, appelez la méthode d'héritage et renvoyez la valeur de retour.

À propos, pour afficher le message, procédez comme suit. Le contenu du document est tel qu'il est.

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

DeleteView

Comme son nom l'indique, «DeleteView» supprime un enregistrement. Le modèle est (AppName) / (AppName) _confirm_delete.html.

views.py


from django.views.generic.edit import DeleteView
from myapp.models import MyModel


class MyDeleteView(DeleteView):
    model = MyModel

Le modèle dans ce cas sera un formulaire de confirmation demandant "Êtes-vous sûr de vouloir le supprimer?"

Il y a peut-être des moments où vous souhaitez simplement activer l'indicateur de suppression au lieu de le supprimer vraiment. Dans un tel cas, il est préférable de remplacer la méthode delete. Cependant, je ne l'ai pas essayé parce que je le supprime docilement.

Articles communs

En plus du traitement mentionné ci-dessus, la vue à usage général basée sur les classes peut remplacer librement le nom du fichier modèle et le nom de la variable. De plus, la méthode est également courante, je vais donc en présenter quelques-unes. Je pense qu'il est généralement préférable d'utiliser la valeur par défaut et de la remplacer uniquement lorsque cela est nécessaire.

Variable par défaut

Comme vous l'avez peut-être déjà remarqué, les vues génériques ont une certaine régularité. Remplacer get_context_data, effectuer le traitement nécessaire et le définir dans une variable a été introduit dans la première étape. Si vous souhaitez transmettre des données à un modèle, cela devrait suffire.

Donc, au contraire, lorsqu'une vue polyvalente récupère automatiquement des données, quel type de données est défini dans quelle variable?

La vue générique basée sur les classes récupère automatiquement les données de la base de données en fonction de leur utilisation prévue (classe héritée). Définissez à partir de quelle table les données sont récupérées comme model = MyModel.

views.py


class MyListView(ListView):
    model = MyModel  #Obtenez automatiquement une liste de MyModels

En faisant cela, vous obtiendrez les données de MyModel. Le résultat, etc. doit être défini dans une variable avec un nom fixe. ʻObject s'il n'y a qu'un seul enregistrement tel qu'une page individuelle. S'il y en a plus d'un, ʻobject_list.

Le modèle ressemblerait à ceci:

Pages individuelles etc.

{{ object }}

S'il y en a plus d'un

{% for item in object_list %}
  {{ item }}
{% endfor %}

Cependant, je ne peux pas dire ce que cela signifie en regardant le modèle. Vous souhaiterez peut-être rendre le nom de la variable plus descriptif. Dans ce cas, attribuez le nom de la variable à context_object_name.

views.py


class MyBookList(ListView):
    model = Books
    context_object_name = "my_books"  #Spécifiez le nom de la variable sur cette ligne

De cette façon, dans le modèle

<ul>
    {% for book in my_books %}
    <li>{{ book.name }}</li>
    {% endfor %}
</ul>

Vous pouvez l'appeler comme ça. Maintenant que vous savez à quoi fait référence le nom de la variable, il est facile de voir à quoi la variable fait référence simplement en lisant le modèle.

Spécification du fichier à utiliser comme modèle

les vues sont des contrôleurs. Par conséquent, transmettez les données au modèle approprié. Le modèle peut être spécifié explicitement, mais il a un nom de modèle par défaut. C'est,

(ModelName)/(ModelName)_(ViewName).html

C'est.

Elles sont,

  • AppName
  • Le nom de l'application créée par manage.py startapp etc.
  • ViewName
  • Noms uniques tels que list pour ListView et detail pour DetailView

C'est supposé être. Autrement dit, l'utilisation de «ListView» avec «myapp» cherchera par défaut «myapp / myapp_list.html».

Si vous souhaitez changer cela

views.py


class MyListView(ListView):
    model = MyModel
    template_name = "my_list_view.html"  #Spécifiez le modèle sur cette ligne

Faire.

De côté

Si vous utilisez une vue générique, vous souhaiterez définir la même variable dans chaque vue. Par exemple, "nom du site". Ce n'est pas bon de le définir dans toutes les vues, donc je me demande si je devrais créer une classe commune et en hériter.

base_view.py


from django.views.generic import ListView

from myapp.models import MyModel


#N'héritez pas de Mixin etc., mais héritez d'un objet.
class MyCommonView(object):

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["SITE_NAME"] = "SITE-NAME"
        return context


class MyListView(ListView, MyCommonView):
    model = MyModel

Maintenant, si vous souhaitez changer le nom du site, vous n'avez qu'à le changer à un seul endroit ...? Ce serait une solution, mais je pense qu'il vaut mieux utiliser le processeur de contexte avec obéissance.

Épilogue

Je suis fatigué.

J'espère que cela aidera ceux qui utilisent Django.

Pour le moment

  • Django 1.9
  • python 3.5.1

J'ai confirmé l'opération avec, mais veuillez me dire s'il y a quelque chose qui ne va pas.

Recommended Posts