[PYTHON] TemplateView les modèles que vous souhaitez apprendre en premier dans Django

TemplateView

Si vous créez un service Web, la majeure partie du traitement du serveur charge un modèle HTML et lui applique des variables d'affichage.

TemplateView (django.views.generic.base.TemplateView) est fourni par Django à cet effet. Bien que ce soit une classe simple, c'est une classe de vue très pratique qui contient les fonctions requises pour la génération de page.

Si vous créez une vue au format de vue basé sur les classes, la plupart des vues HTTP GET du navigateur seront écrites dans TemplateView.

Dans le cas de POST, je pense qu'il existe de nombreux processus tels que l'utilisation de FormView, le traitement avec une vue brute et le retour de HttpResponseRedirect. (Cela dépend du contenu du service)

TemplateView peut être écrit dans divers modèles en raison des caractéristiques du langage de Python. Laquelle est la meilleure est au cas par cas, mais j'écrirai quelques-unes des méthodes que j'écris souvent.

Prérequis (environnement)

+ manage.py
+ myapp
  + models.py
  + urls.py
  + views.py
  + templates
    + myapp
      + index.html

Supposons que vous ayez ce type de structure de répertoires.

Supposons également que settings.INSTALLED_APPS contient myapp et que settings.TEMPLATE_LOADERS contient django.template.loaders.app_directories.Loader.

1. Un modèle qui donne un argument à as_view avec des URL

De base

Non limité à TemplateView, il s'agit d'une fonction de View ( django.views.generic.base.View), mais il a une fonction pour stocker automatiquement l'argument mot-clé donné au constructeur dans la variable d'instance. Lors de la conversion en fonction de vue avec ʻas_view () , tous les arguments de ʻas_view () sont généralement les arguments du constructeur de la classe de vue.

Et parce que TemplateView utilise la variable d'instance nom_modèle comme modèle par défaut,

urls.py



urlpatterns = [
    url(r'^myapp/$', TemplateView.as_view(template_name='myapp/index.html'),
        name='myapp-index'),
    ...

Si vous écrivez ceci, lorsque vous demandez myapp / dans le navigateur, le contenu de myapp / index.html sera évalué et affiché dans le navigateur.

ʻAs_view () Lorsqu'elle est exécutée, une fonction de vue encapsulée comme un décorateur est générée, mais l'argument mot-clé y est lié, et lorsque l'utilisateur le demande réellement, TemplateView (template_name = 'myapp / index. " html ') ʻun traitement de construction équivalent fonctionne, la méthode get fonctionne et une réponse est créée.

application

En tant que fonction de TemplateView ou ContextMixin, la classe de vue instanciée est utilisée comme argument de modèle nommé view.

urls.py



urlpatterns = [
    url(r'^myapp/a/$', TemplateView.as_view(template_name='myapp/index.html', mode='a'),
        name='myapp-a'),
    url(r'^myapp/b/$', TemplateView.as_view(template_name='myapp/index.html', mode='b'),
        name='myapp-b'),   ...

Gardez-le dans des URL comme celle-ci et utilisez le modèle

myapp/index.html



{% if view.mode == 'a' %}
Affichage du mode A
{% elif view.mode == 'b' %}
Affichage du mode B
{% endif %}

Vous pouvez également dériver l'affichage de cette manière.

De plus, en fonction de View, request, kwargs, etc. sont automatiquement ajoutés à l'argument d'instance, donc

urls.py



urlpatterns = [
    url(r'^myapp/(?P<mode_name>\w+)/$', TemplateView.as_view(template_name='myapp/index.html'),
        name='myapp-index'),
    ...

myapp/index.html


{{ view.kwargs.mode_name }}mode<br />
Bonjour! {{ view.request.user.username }}

Ce type d'affichage peut être réalisé avec juste un modèle sans écrire de code Python autre que des URL.

2. Modèle pour remplacer la méthode get

Un modèle qui crée un contexte de modèle dans get sans appeler le parent get

Ce modèle est souvent utilisé lorsque vous souhaitez écrire le traitement des vues de manière procédurale.

myapp/views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'

    def get(self, request, **kwargs):
Traitement procédural...
        context = {
            'items': ....
        }
        return self.render_to_response(context)

Le processus est intuitif et facile à comprendre.

Lorsqu'il s'agit d'un traitement compliqué, la méthode devient longue verticalement, donc dans un tel cas, il est préférable d'envoyer le traitement à une autre classe. En ce qui concerne les modèles, je pense que cela fonctionne généralement bien si vous mettez des méthodes dans le modèle ou dans le gestionnaire de modèles (MyAppModel.objects ← ce type).

Pour un exemple d'extension du gestionnaire de modèles et des méthodes de génération, AbstractUser dans django.contrib.auth.models utilise UserManager comme gestionnaire.

En passant, si vous écrivez comme indiqué ci-dessus, vous ne pourrez pas faire référence à l'instance de vue dans la vue à partir du modèle, donc si vous souhaitez faire référence à la vue à partir du modèle

    context = {
        'view': self,
        'items': ....
    }

Vous pouvez également inclure explicitement la vue de cette manière.

Personnellement, quand je veux remplacer la méthode get de TemplateView, je pense que je devrais me calmer et réfléchir à ce dont j'ai vraiment besoin. Si vous souhaitez obtenir une instance de modèle, vous pouvez rendre chaque processus fragmenté et réduire le risque d'effets secondaires du processus en remplaçant get_context_data décrit plus loin ou en créant une méthode en vue.

Modèle pour appeler le parent get

myapp/views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'

    def get(self, request, **kwargs):
        if XXX:
            return HttpResponseBadRequest(...)
        return super().get(request, **kwargs)
        # python2: return super(IndexView, self).get(request, **kwargs)

C'est une forme plus familière dans les langages orientés objet. Ce n'est pas un modèle de jouer avec le contexte du modèle, il a donc des capacités limitées et des utilisations limitées. Il est souvent utilisé lorsque vous souhaitez écrire uniquement le processus qui renvoie une erreur à la requête.

3. Modèle qui remplace get_context_data

Si le remplacement de get ne semble pas être une logique sale, c'est une bonne idée de remplacer la méthode ContextMixin get_context_data.

myapp/views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['items'] = ...
        ctx[xxx] = ...
        return ctx

Ça ressemble à ça.

Si vous souhaitez créer une classe de base qui étend TemplateView, puis l'étendre (hériter en plusieurs étapes) pour créer une classe de vue réelle, il est plus simple d'écrire pour remplacer get_context_data plutôt que de remplacer get. J'ai l'impression de pouvoir le lire.

Désormais, contrairement à la substitution de get, il semble que vous ne puissiez pas accéder à l'argument de la requête, mais à cause de la fonctionnalité View, la requête concerne les variables d'instance.

myapp/views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['authenticated'] = self.request.user.is_authenticated
        ctx[xxx] = self.request.session.get(...)
        return ctx

De cette façon, vous pouvez traiter les demandes sans aucun problème.

L'argument kwargs de get_context_data contient le contenu qui correspond à l'espace réservé de l'expression régulière nommée spécifiée dans urls.py, mais ce contenu est également inclus dans self.kwargs et est accessible, il est donc un peu redondant. J'en ai envie.

4. Et cached_property

La classe View fonctionne très bien avec cached_property (django.utils.functional.cached_property) car elle est instanciée sur demande.

myapp/views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'

    @cached_property
    def items(self):
        """Liste des objets possédés"""
        return Item.objects.filter(user=self.request.user)

    @cached_property
    def power_total(self):
        """Pouvoir total"""
        return sum(i.power for i in self.items)

    @cached_property
    def power_average(self):
        """Puissance moyenne"""
        return self.power_total / len(self.items)

    def _get_special_items(self):
        """Générateur qui extrait uniquement les éléments spéciaux des éléments"""
        for item in self.items:
            if item.is_not_special:
                continue
            if ....:
                continue
            yield item

    @cached_property
    def special_power_total(self):
         """Puissance totale des objets spéciaux"""
         return sum(i.power for i in self._get_special_items())

    @cached_property
    def special_power_rate(self):
         """Rapport de puissance totale des articles spéciaux et de tous les articles"""
         return self.special_power_total / self.power_total

myapp/index.html


Pouvoir total: {{ view.power_total }}
Puissance spéciale totale: {{ view.special_power_total }}
Tarif spécial: {{ view.special_power_rate }}

Eh bien, dans cet exemple, il est dit que ** Créez une classe séparée qui résume les éléments sans l'écrire dans la vue! **, mais vous pouvez l'écrire comme ceci à titre d'exemple.

L'utilisation de cached_property garantit qu'un traitement intensif ne s'exécutera qu'une seule fois dans la vue sans aucune attention particulière, ce qui lui confère une bonne visibilité et une bonne vitesse de traitement. Vous n'avez pas à vous soucier de la relation hiérarchique du traitement.

Par exemple, dans cet exemple, la méthode items a @ cached_property, donc le SQL pour rechercher le modèle Item n'est émis qu'une seule fois, et le processus de sommation de la somme des puissances de tous les éléments n'est effectué qu'une seule fois. Je comprends.

Je pense que c'est une façon d'écrire du code semblable à Python, mais qu'en est-il?

Mise en cache des résultats de la génération HTML

La meilleure façon de mettre en cache les résultats de la génération HTML dans un cache commun est d'utiliser le décorateur django.views.decorators.cache_page, comme le dit la documentation Django.

Parce que vous pouvez décorer le résultat de as_view

urls.py



urlpatterns = [
    url(r'^myapp/(?P<mode_name>\w+)/$',
        cache_page(3600)(TemplateView.as_view(template_name='myapp/index.html')),
        name='myapp-index'),
    ...

Ample

views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'
    ....

index_view = cache_page(3600)(IndexView.as_view())

urls.py


urlpatterns = [
    url(r'^myapp/(?P<mode_name>\w+)/$',
        'index_view',
        name='myapp-index'),
    ...

Je pense que c'est un modèle que j'utilise souvent. login_required est le même.

views.py


class MyPageView.as_view(TemplateView):
    template_name = 'mypage/index.html'
    ....

mypage_view = login_required(MyPageView.as_view())

Si vous utilisez django.utils.decorators.method_decorator, il transformera la fonction de décorateur afin qu'elle puisse être appliquée à la méthode liée.

views.py


class IndexView(TemplateView):
    template_name = 'myapp/index.html'
    
    @method_decorator(cache_page(3600))
    def get(....):
        ....

C'est également une bonne idée si vous souhaitez décorer la méthode get.

Si vous n'aimez pas redéfinir la méthode get, vous pouvez le faire dans la commande as_view remplacée.

views.py


class IndexView(TemplateView):
    template_name = '...'

    @classonlymethod
    def as_view(cls, **initkwargs):
        return cache_page(3600)(
            super().as_view(**initkwargs)

Cas où vous souhaitez gérer HTTP POST

Dans une application Web qui renvoie du HTML, si vous êtes sur le point d'écrire un def post (...) dans unTemplateView, calmons-nous.

Peut-être que FormView est meilleur que TemplateView.

FormView a une fonction qui fonctionne avec le formulaire de Django pour «vous inviter à ressaisir tout en affichant un affichage d'erreur lorsqu'il y a une erreur dans le formulaire». "S'il n'y a pas d'erreur dans le formulaire, effectuez un ◯◯ traitement" est également préparé comme méthode modèle. Pourquoi n'y pensez-vous pas?

Vue générique Postscript CRUD

J'ai écrit sur CRUD Generic View sur mon blog. Vues génériques CRUD de Django faciles à utiliser (ListView, DetailView, CreateView, UpdateView, DeleteView)

Recommended Posts

TemplateView les modèles que vous souhaitez apprendre en premier dans Django
Je veux corriger Datetime.now dans le test de Django
[Django] Je souhaite me connecter automatiquement après une nouvelle inscription
Erreur liée à memcached dans django
Comment refléter CSS dans Django
Je veux gratter des images et les former
Je souhaite utiliser Django Debug Toolbar dans les applications Ajax
Je veux imprimer dans la notation d'inclusion
Comment supprimer des sessions expirées dans Django
[Django] Vous souhaitez personnaliser la page d'administration?
L'utilisateur non connecté de Django souhaite passer à login.html
Je veux intégrer Matplotlib dans PySimpleGUI
Comment faire des événements envoyés par le serveur dans Django
Si vous souhaitez afficher la valeur à l'aide des choix du modèle dans le modèle Django
[Django memo] Je souhaite définir à l'avance les informations de l'utilisateur connecté dans le formulaire.
La première chose à vérifier quand un No Reverse Match se produit dans Django
Scraping avec Python - Introduction à Scrapy Première 2e étape
Premiers pas pour essayer Google CloudVision en Python
Je veux faire le test de Dunnett en Python
Ajouter dynamiquement des champs aux objets Form avec Django
Comment implémenter la fonctionnalité de type helper Rails dans Django
Comment refléter ImageField dans Django + Docker (oreiller)
Je souhaite stocker les informations de la base de données dans la liste
Je veux fusionner des dictionnaires imbriqués en Python
Passer les informations de connexion à afficher dans Django
Comment créer une API Rest dans Django
Je veux afficher la progression en Python!
Je souhaite télécharger une application Django sur heroku
Je souhaite créer une base de données de déjeuners [EP1] Django pour la première fois
Je souhaite créer une base de données de déjeuner [EP1-4] Django pour la première fois
Je souhaite envoyer un message d'erreur en japonais avec le formulaire de changement de mot de passe django