[PYTHON] TemplateView-Muster, die Sie zuerst in Django lernen möchten

TemplateView

Wenn Sie einen Webdienst erstellen, lädt der Großteil der Serververarbeitung eine HTML-Vorlage und wendet Anzeigevariablen darauf an.

TemplateView (django.views.generic.base.TemplateView) wird zu diesem Zweck von Django bereitgestellt. Obwohl es sich um eine einfache Klasse handelt, handelt es sich um eine sehr praktische Ansichtsklasse, die die für die Seitengenerierung erforderlichen Funktionen enthält.

Wenn Sie eine Ansicht im klassenbasierten Ansichtsformat erstellen, werden die meisten Ansichten von HTTP GET aus dem Browser in TemplateView geschrieben.

Im Fall von POST gibt es meines Erachtens viele Prozesse, z. B. die Verwendung von FormView, die Verarbeitung mit Rohansicht und die Rückgabe von HttpResponseRedirect. (Es hängt vom Service-Inhalt ab)

TemplateView kann aufgrund der Spracheigenschaften von Python in verschiedenen Mustern geschrieben werden. Welches besser ist, ist von Fall zu Fall, aber ich werde einige der Methoden schreiben, die ich oft schreibe.

Voraussetzungen (Umgebung)

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

Angenommen, Sie haben diese Art von Verzeichnisstruktur.

Nehmen Sie außerdem an, dass "settings.INSTALLED_APPS" "myapp" und "settings.TEMPLATE_LOADERS" "django.template.loaders.app_directories.Loader" enthält.

1. Ein Muster, das as_view mit URLs ein Argument gibt

Basic

Es ist nicht auf "TemplateView" beschränkt, sondern eine Funktion von "View" ("django.views.generic.base.View"), verfügt jedoch über eine Funktion zum automatischen Speichern des dem Konstruktor angegebenen Schlüsselwortarguments in der Instanzvariablen. Bei der Konvertierung in eine Ansichtsfunktion mit "as_view ()" sind normalerweise alle Argumente von "as_view ()" die Konstruktorargumente der Ansichtsklasse.

Und weil TemplateView standardmäßig die Instanzvariable template_name als Vorlage verwendet,

urls.py



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

Wenn Sie dies schreiben und myapp / im Browser anfordern, wird der Inhalt von myapp / index.html ausgewertet und an den Browser ausgegeben.

Wenn "as_view ()" ausgeführt wird, wird eine Ansichtsfunktion generiert, die wie ein Dekorator verpackt ist, aber das Schlüsselwortargument darin gebunden ist, und wenn der Benutzer es tatsächlich anfordert, "TemplateView (template_name =" myapp / index ". html ') `äquivalente Konstruktverarbeitung funktioniert, Methode funktioniert und eine Antwort wird erstellt.

Anwendung

In Abhängigkeit von TemplateView oder ContextMixin wird die instanziierte Ansichtsklasse als Vorlagenargument mit dem Namen view verwendet.

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'),   ...

Behalten Sie es in solchen URLs und verwenden Sie die Vorlage

myapp/index.html



{% if view.mode == 'a' %}
Modus Eine Anzeige
{% elif view.mode == 'b' %}
Modus B Anzeige
{% endif %}

Auf diese Weise können Sie die Anzeige auch verzweigen.

In Abhängigkeit von Ansicht werden dem Instanzargument automatisch Anforderungen, Anforderungen, Warnungen usw. hinzugefügt

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 }}Modus<br />
Hallo! {{ view.request.user.username }}

Diese Art der Anzeige kann mit nur einer Vorlage erreicht werden, ohne dass ein anderer Python-Code als URLs geschrieben werden muss.

2. Muster zum Überschreiben der get-Methode

Ein Muster, das einen Vorlagenkontext in get erstellt, ohne das übergeordnete get aufzurufen

Dieses Muster wird häufig verwendet, wenn Sie die Ansichtsverarbeitung prozedural schreiben möchten.

myapp/views.py


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

    def get(self, request, **kwargs):
Verfahrensabwicklung...
        context = {
            'items': ....
        }
        return self.render_to_response(context)

Der Prozess ist intuitiv und leicht zu verstehen.

Wenn es um eine komplizierte Verarbeitung geht, wird die Methode vertikal lang. In einem solchen Fall ist es besser, die Verarbeitung an eine andere Klasse zu senden. Wenn Sie mit Modellen arbeiten, funktioniert es normalerweise gut, wenn Sie Methoden in das Modell oder in den Modellmanager einfügen (MyAppModel.objects ← this guy).

Ein Beispiel für die Erweiterung des Modellmanagers und der Spawning-Methoden finden Sie in dem Fall, in dem AbstractUser in django.contrib.auth.models UserManager als Manager verwendet.

Wenn Sie wie oben gezeigt schreiben, können Sie übrigens nicht auf die Ansichtsinstanz in der Ansicht aus der Vorlage verweisen. Wenn Sie also auf die Ansicht aus der Vorlage verweisen möchten

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

Sie können die Ansicht auch explizit wie folgt einfügen.

Persönlich denke ich, wenn ich die get-Methode von TemplateView überschreiben möchte, sollte ich mich beruhigen und darüber nachdenken, was ich wirklich brauche. Wenn Sie eine Modellinstanz erhalten möchten, können Sie jeden Prozess sparsam gestalten und das Risiko von Nebenwirkungen des Prozesses verringern, indem Sie die später beschriebenen get_context_data überschreiben oder eine angezeigte Methode erstellen.

Muster zum Aufrufen der Eltern erhalten

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)

Dies ist eine bekanntere Form in objektorientierten Sprachen. Es ist kein Muster, mit dem Vorlagenkontext in Konflikt zu geraten, daher hat es begrenzte Funktionen und begrenzte Verwendungsmöglichkeiten. Es wird häufig verwendet, wenn Sie nur den Prozess schreiben möchten, der einen Fehler an die Anforderung zurückgibt.

3. Muster, das get_context_data überschreibt

Wenn das Überschreiben von get nicht wie eine schmutzige Logik erscheint, empfiehlt es sich, die ContextMixin-Methode get_context_data zu überschreiben.

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

Es sieht aus wie das.

Wenn Sie eine Basisklasse erstellen möchten, die TemplateView erweitert und dann erweitert (in mehreren Schritten geerbt), um eine tatsächliche Ansichtsklasse zu erstellen, ist es einfacher zu schreiben, um get_context_data zu überschreiben, als get zu überschreiben. Ich habe das Gefühl, ich kann es lesen.

Anders als beim Überschreiben von get sieht es so aus, als könnten Sie nicht auf das Anforderungsargument zugreifen, aber aufgrund der Ansichtsfunktion handelt es sich bei der Anforderung um Instanzvariablen.

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

Auf diese Weise können Sie Anfragen problemlos bearbeiten.

Das kwargs-Argument von get_context_data enthält den Inhalt, der mit dem Platzhalter des in urls.py angegebenen benannten regulären Ausdrucks übereinstimmt. Dieser Inhalt ist jedoch auch in self.kwargs enthalten und kann abgerufen werden, sodass er etwas redundant ist. Ich fühle mich wie es.

4. Und cached_property

Die View-Klasse funktioniert sehr gut mit cached_property (django.utils.functional.cached_property), da sie auf Anfrage instanziiert wird.

myapp/views.py


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

    @cached_property
    def items(self):
        """Liste der besessenen Gegenstände"""
        return Item.objects.filter(user=self.request.user)

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

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

    def _get_special_items(self):
        """Generator, der nur spezielle Elemente aus Elementen extrahiert"""
        for item in self.items:
            if item.is_not_special:
                continue
            if ....:
                continue
            yield item

    @cached_property
    def special_power_total(self):
         """Gesamtleistung von Spezialgegenständen"""
         return sum(i.power for i in self._get_special_items())

    @cached_property
    def special_power_rate(self):
         """Gesamtleistungsverhältnis von Spezialgegenständen und allen Gegenständen"""
         return self.special_power_total / self.power_total

myapp/index.html


Totale Kraft: {{ view.power_total }}
Totale Spezialkraft: {{ view.special_power_total }}
Sonderpreis: {{ view.special_power_rate }}

In diesem Beispiel heißt es: ** Erstellen Sie eine separate Klasse, die Elemente zusammenfasst, ohne sie in der Ansicht zu schreiben! **, aber Sie können sie als Beispiel so schreiben.

Die Verwendung von cached_property garantiert, dass schwere Verarbeitung nur einmal in der Ansicht ohne besondere Aufmerksamkeit ausgeführt wird, sodass eine gute Sichtbarkeit und Verarbeitungsgeschwindigkeit erzielt werden. Sie müssen sich nicht um die hierarchische Beziehung der Verarbeitung kümmern.

In diesem Beispiel hat die items-Methode beispielsweise "@ cached_property", sodass die SQL zum Durchsuchen des Item-Modells nur einmal ausgegeben wird und der Vorgang des Summierens der Gesamtleistung aller Items auch nur einmal ausgeführt wird. Ich verstehe.

Ich denke, es ist eine Python-ähnliche Art, Code zu schreiben, aber was ist damit?

Zwischenspeichern der Ergebnisse der HTML-Generierung

Der beste Weg, um HTML-Generierungsergebnisse in einem gemeinsamen Cache zwischenzuspeichern, ist die Verwendung des Dekorators django.views.decorators.cache_page, wie in der Django-Dokumentation angegeben.

Weil Sie das Ergebnis von as_view dekorieren können

urls.py



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

Lose

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'),
    ...

Ich denke, es ist ein Muster, das ich oft benutze. login_required ist das gleiche.

views.py


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

mypage_view = login_required(MyPageView.as_view())

Wenn Sie django.utils.decorators.method_decorator verwenden, wird die Decorator-Funktion so transformiert, dass sie auf die gebundene Methode angewendet werden kann.

views.py


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

Dies ist auch eine gute Idee, wenn Sie die get-Methode dekorieren möchten.

Wenn Sie die get-Methode nicht gerne überschreiben, können Sie dies in der überschriebenen as_view tun.

views.py


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

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

Fälle, in denen Sie HTTP POST verarbeiten möchten

Wenn Sie in einer Web-App, die HTML zurückgibt, einen "def post (...)" in einer "TemplateView" schreiben möchten, lassen Sie uns beruhigen.

Vielleicht ist FormView besser als TemplateView.

FormView verfügt über eine Funktion, die mit dem Formular von Django zusammenarbeitet und Sie zur erneuten Eingabe auffordert, während eine Fehleranzeige angezeigt wird, wenn ein Fehler im Formular vorliegt. "Wenn das Formular keinen Fehler enthält, führen Sie die Verarbeitung durch" wird auch als Vorlagenmethode bereitgestellt. Warum denkst du nicht darüber nach?

Postscript CRUD Generische Ansicht

Ich habe in meinem Blog über CRUD Generic View geschrieben. Einfach zu verwendende generische CRUD-Ansichten von Django (ListView, DetailView, CreateView, UpdateView, DeleteView)

Recommended Posts

TemplateView-Muster, die Sie zuerst in Django lernen möchten
Ich möchte Datetime.now in Djangos Test reparieren
[Django] Ich möchte mich nach einer neuen Registrierung automatisch anmelden
Fehler im Zusammenhang mit Memcached in Django
Wie man CSS in Django reflektiert
Ich möchte Bilder kratzen und trainieren
Ich möchte die Django Debug Toolbar in Ajax-Anwendungen verwenden
Ich möchte in der Einschlussnotation drucken
So löschen Sie abgelaufene Sitzungen in Django
[Django] Möchten Sie die Administrationsseite anpassen?
Nicht angemeldeter Django-Benutzer möchte zu login.html wechseln
Ich möchte Matplotlib in PySimpleGUI einbetten
So führen Sie vom Server gesendete Ereignisse in Django durch
Wenn Sie den Wert mithilfe von Auswahlmöglichkeiten in der Vorlage im Django-Modell anzeigen möchten
[Django-Memo] Ich möchte die angemeldeten Benutzerinformationen im Voraus im Formular festlegen.
Das erste, was überprüft werden muss, wenn in Django ein No Reverse Match auftritt
Scraping mit Python-Einführung in Scrapy Erster 2. Schritt
Erste Schritte zum Testen von Google CloudVision in Python
Ich möchte Dunnetts Test in Python machen
Fügen Sie Formularobjekten mit Django dynamisch Felder hinzu
So implementieren Sie Rails-Helfer-ähnliche Funktionen in Django
So reflektieren Sie ImageField in Django + Docker (Kissen)
Ich möchte DB-Informationen in einer Liste speichern
Ich möchte verschachtelte Dicts in Python zusammenführen
Übergeben Sie Login-Benutzerinformationen, um sie in Django anzuzeigen
So erstellen Sie eine Rest-API in Django
Ich möchte den Fortschritt in Python anzeigen!
Ich möchte eine Django-App auf Heroku hochladen
Ich möchte zum ersten Mal eine Django-Studie zur Mittagsdatenbank [EP1] erstellen
Ich möchte zum ersten Mal eine Django-Studie zum Mittagessen [EP1-4] erstellen
Ich möchte eine Fehlermeldung auf Japanisch mit dem Django-Passwortänderungsformular ausgeben