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.
+ 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.
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.
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.
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.
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.
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.
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?
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)
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?
Ich habe in meinem Blog über CRUD Generic View geschrieben. Einfach zu verwendende generische CRUD-Ansichten von Django (ListView, DetailView, CreateView, UpdateView, DeleteView)