" platzieren.
Wenn Sie in derselben Ansicht empfangen möchten, müssen Sie keine Aktion angeben.
Dieses Mal schreibe ich es nur in leeren Zeichen.
Bitte beachten Sie, dass beim Senden von Daten per POST "csrf_token" erforderlich ist.
Erklärung von csrf → [Jeder liebt Wikipedia](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)
Da die POST-Kommunikation eine HTML-Datenübertragung zum Server ist (= Änderung der Serverinformationen)
Wie es eingegeben wurde, ist wichtig.
In Django können Sie durch Hinzufügen des Tags "csrf_token" sicherstellen, dass die Daten auf der von Ihnen vorbereiteten Seite eingegeben wurden.
Das modifizierte HTML ist wie folgt.
polls/templates/polls/form.html
<html>
<body>
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Senden"/>
</form>
</body>
</html>
Stellen Sie sicher, dass die Schaltfläche im Browser angezeigt wird
Selbst wenn Sie die Taste drücken, passiert nichts, weil danach nichts mehr geschrieben wird.
Wenn Sie sich das Protokoll auf dem Bildschirm ansehen, auf dem "runsever" ausgeführt wird, können Sie bestätigen, dass die POST-Kommunikation ausgeführt wird.
(tutorial)$ ./manage.py runserver 127.0.0.1:13000
Performing system checks...
System check identified no issues (0 silenced).
February 21, 2016 - 16:56:38
Django version 1.9.2, using settings 'tutorial.settings'
Starting development server at http://127.0.0.1:13000/
Quit the server with CONTROL-C.
[21/Feb/2016 17:34:28] "GET /polls/form HTTP/1.1" 200 343 #← Bildschirmanzeige
[21/Feb/2016 17:34:30] "POST /polls/form HTTP/1.1" 200 343 #← Klicken Sie auf "Senden"
Übrigens, wenn Sie vergessen, das Tag "{% csrf_token%}" in HTML zu schreiben, wird es so sein.

Dieser Überprüfungsprozess wird von MIDDLEWARE ausgeführt, und Sie können anhand von settings.py feststellen, dass er standardmäßig festgelegt ist.
tutorial/settings.py
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', #←←←←←←←← csrf Check-Verarbeitung
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)
Datenempfangsverarbeitung
Quelle → 8ea545ce
Die empfangenen POST-Daten werden in der Anforderungsklasse mit dem Namen "POST" gespeichert.
Übergeben Sie diese Daten an die Form-Klasse, überprüfen Sie die Gültigkeit der Daten und führen Sie bei korrekter Verarbeitung eine Verarbeitung mit diesen Daten durch.
Die geänderte Ansicht sieht folgendermaßen aus.
polls/views.py
def form_test(request):
if request.method == "POST":
form = MyForm(data=request.POST) #← Übergeben Sie die empfangenen POST-Daten
if form.is_valid(): #← Bestätigung der Gültigkeit der empfangenen Daten
pass #← Verarbeitung, wenn korrekte Daten empfangen werden
else: #← Methode ist'POST'ist nicht=Verarbeitung, wenn die erste Seite angezeigt wird
form = MyForm()
return render(request, 'polls/form.html', {
'form': form,
})
Nach dem Empfang der korrekten Daten werden die Daten in der Datenbank usw. registriert und eine Verarbeitung wie das Umleiten auf eine andere Seite wird durchgeführt.
Ich habe diesmal nichts getan.
Lassen Sie uns den Vorgang im Browser in diesem Zustand überprüfen.
Sie sollten eine Fehlermeldung sehen, wenn Sie auf die Schaltfläche "Senden" klicken, ohne etwas in "Text" einzugeben.

Feldanpassung
Quelle → 5637b54
Sie können das Verhalten und die Ausgabe eines Felds ändern, indem Sie beim Erstellen ein Argument übergeben.
Das Übergeben von "erforderlich = falsch" führt beispielsweise nicht zu einem Fehler, selbst wenn in diesem Feld kein Eingabewert vorhanden ist.
Sie können das Zeichen von "Text" auch ändern, indem Sie das Argument "label" hinzufügen.
Im Folgenden finden Sie die Argumente, die angegeben werden können.
https://docs.djangoproject.com/en/1.9/ref/forms/fields/#core-field-arguments
Dieses Mal setzen wir das zuvor erläuterte "Erforderlich" und "Etikett".
polls/forms.py
class MyForm(forms.Form):
text = forms.CharField(max_length=100, required=False, label='Text')

Text ist jetzt Text.
Ich denke auch, dass Sie bestätigen können, dass die Fehlermeldung verschwunden ist, selbst wenn Sie auf Senden geklickt haben, ohne etwas einzugeben.
Formular für die Abstimmung
Erstellen eines Abstimmungsformulars
Quelle → 9077adee
Schreiben wir das in Tutorial 4 erstellte Abstimmungsformular mithilfe der Form-Klasse neu.
Die erforderliche Eingabe ist ein Optionsfeld zum Auswählen der Liste der Auswahlmöglichkeiten, die dem "Fragen" -Modell zugeordnet sind.
Mit ModelChoiceField kann ein Modell ausgewählt werden.
Dieses Feld erfordert ein Abfrageset, um das Modell auszuwählen, aber bei der Definition des Feldes, für das "Frage"
Da es ungewiss ist, ob es sich um ein Formular handelt, überschreiben wir die Methode init und erhalten sie als Argument.
polls/forms.py
class VoteForm(forms.Form):
choice = forms.ModelChoiceField(
queryset=None,
label='Wahl',
widget=forms.RadioSelect(),
empty_label=None,
error_messages={
'required': "You didn't select a choice.",
'invalid_choice': "invalid choice.",
},
)
def __init__(self, question, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['choice'].queryset = question.choice_set.all()
Da das Standard-Widget von ModelChoiceField eine Auswahlliste ist, geben Sie RadioSelect als Widget an.
Setzen Sie das Abfrageset vorerst auf "Keine" und überschreiben Sie es mit dem Argument in "init".
Durch Setzen von error_messages können Sie Fehlermeldungen angeben, wenn verschiedene ungültige Werte eingegeben werden.
Wenn hier nicht angegeben (erforderlich) und wenn ein nicht ausgewählter Wert eingegeben wird (invalid_choice)
Eine Fehlermeldung wird gesetzt.
Als nächstes löschen wir das Formular, das durch Umschreiben von views.py und Vorlagen erstellt wurde.
polls/views.py
from .forms import VoteForm
def detail(request, pk):
obj = get_object_or_404(Question, pk=pk)
form = VoteForm(question=obj)
return render(request, 'polls/detail.html', {
'form': form,
'question': obj,
})
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Vote" />
</form>
Überprüfen Sie mit dem Browser
Die Wahl ist "Wahlobjekt".
Wie ich in Tutorial 2 ein wenig erwähnt habe, sieht die Zeichenfolgendarstellung einer Instanz standardmäßig wie "ModelName-Objekt" aus.
Öffnen Sie models.py und überschreiben Sie die Methode str.
polls/models.py
class Choice(models.Model):
...
def __str__(self):
return self.choice_text

Es hat sich richtig geändert.
Im Gegensatz zum ersten Bildschirm befindet sich vor jeder Option ein zusätzlicher schwarzer Fleck.
Dies liegt daran, dass standardmäßig jede Option durch ein <li> -Tag getrennt ist.
Es ist vorzuziehen, das Auftreten schwarzer Flecken in CSS zu verhindern.
Wenn Sie das HTML wirklich ändern möchten, können Sie das innere_html des vom Widget gehaltenen Renderers neu schreiben.
polls/forms.py
class VoteForm(forms.Form):
def __init__(self, question, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['choice'].queryset = question.choice_set.all()
self.fields['choice'].widget.renderer.inner_html = '{choice_value}{sub_widgets}<br>'

Beschreibung des Empfangsprozesses
Quelle → 56f2b498
In Tutorial 4 haben wir eine Funktion zum Empfangen von Stimmen bereitgestellt, die als "Abstimmung" bezeichnet wird. Sie muss jedoch nicht getrennt werden.
Beschreiben wir die Verzweigungsverarbeitung, wenn "POST" abgeschlossen ist, wie beim Schreiben mit "form_test".
polls/views.py
def detail(request, pk):
obj = get_object_or_404(Question, pk=pk)
if request.method == "POST":
form = VoteForm(question=obj, data=request.POST)
if form.is_valid():
# TODO:Abstimmungsprozess
return redirect('polls:results', pk)
else:
form = VoteForm(question=obj)
return render(request, 'polls/detail.html', {
'form': form,
'question': obj,
})
Vergessen Sie nicht, die HTML-Seite so zu korrigieren, dass sie ins Detail springt, anstatt abzustimmen.
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Vote" />
</form>
In Aktion löschen.
Übrigens wird auch "error_message" gelöscht, da die Form-Klasse es automatisch ausgibt.
Beschreibung der Nachbearbeitung
Quelle → 38eb2ec47
Es ist endlich die letzte Arbeit.
Verschieben wir den Abstimmungsprozess (das Hinzufügen von +1 zu den Stimmen der ausgewählten Auswahl und das Speichern), der in views.vote durchgeführt wurde, in die Form-Klasse.
Was Sie tun möchten
polls/views.py
def vote(request, pk):
question = get_object_or_404(Question, pk=pk)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
return redirect('polls:results', pk)
Schreiben Sie also einen Prozess, um die Stimmen der ausgewählten Choice-Instanz in der Form-Klasse zu erhöhen.
Wenn die Form-Klasse "is_valid ()" ausführt, werden die Daten, die durch Konvertieren des Eingabewerts in ein geeignetes Format erhalten werden, in "bereinigte_Daten" aufgenommen.
Es ist ein bisschen verwirrend, aber wählen Sie es aus HTML mit dem Optionsfeld und wählen Sie es aus.
Die an den Server übergebenen Daten sind eine pk-Zeichendarstellung der Choice-Instanz, z. B. "2" oder "3".
Wenn Sie "is_valid ()" ausführen, wird es in eine ** Choice-Instanz konvertiert und in bereinigte_Daten eingefügt.
bereinigte_Daten ist im Wörterbuchformat mit jedem Feldnamen als Schlüssel, um eine Auswahlinstanz zu verwenden
Schreiben Sie als "self.cleaned_data ['choice']".
Wenn Sie auf der Grundlage des oben Gesagten eine Abstimmungsmethode schreiben, die die Stimmen der ausgewählten Choice-Instanz erhöht, ist dies wie folgt.
polls/forms.py
class VoteForm(forms.Form):
...
def vote(self):
assert(self.is_valid())
choice = self.cleaned_data['choice']
choice.votes += 1
choice.save()
assert wird geschrieben, um zu verdeutlichen, dass is_valid () ausgeführt wurde und der Eingabewert gültig sein muss.
Rufen Sie die Abstimmungsmethode nach dem Erstellen von der Ansichtsseite aus auf.
polls/views.py
def detail(request, pk):
obj = get_object_or_404(Question, pk=pk)
if request.method == "POST":
form = VoteForm(question=obj, data=request.POST)
if form.is_valid():
form.vote() #←←←←←←←←←←←←← dies hinzufügen
return redirect('polls:results', pk)
else:
form = VoteForm(question=obj)
return render(request, 'polls/detail.html', {
'form': form,
'question': obj,
})
Damit ist der Vorgang abgeschlossen.
Da views.vote nicht mehr benötigt wird, löschen wir es.
Vergessen Sie nicht, es auch aus urls.py zu löschen.
Feld und Widget
Das Feld entspricht den intern gespeicherten Daten.
Im Fall von "CharField" sind die internen Daten (bereinigte_Daten) beispielsweise ein Texttyp.
Wenn es sich um "IntegerField" handelt, handelt es sich um einen numerischen Typ, und wenn es sich wie diesmal um "ModelChoiceField" handelt, handelt es sich um eine Instanz des ausgewählten Modells.
Andererseits ist das Widget eine GUI, die angibt, welche Art von Teilen im Browser angezeigt werden sollen.
Im Fall von "ModelChoiceField" handelt es sich standardmäßig um eine Auswahlliste, die Sie jedoch in ein Optionsfeld wie dieses ändern können.
Es ist auch möglich, das Textfeld zu erstellen (obwohl es als Eingabe am schlechtesten ist) und die Auswahl pk direkt einzugeben.
Es gibt auch ein Widget, mit dem Sie Datum und Uhrzeit separat eingeben können, z. B. "SplitDateTimeWidget".
Es ist zunächst leicht zu verwirren, aber wir entscheiden, welche Sie ändern möchten, indem wir überlegen, ob Sie die internen Daten oder die Anzeige im Browser ändern möchten.
Zusammenarbeit mit klassenbasierter Allzweckansicht
Umschreiben der Funktion test_form
Quelle → 7d19e395
FormView wird in Django als Allzweckansicht bereitgestellt.
Schreiben wir zunächst form_test mit dieser Klasse neu.
Übrigens ist die neu zu schreibende form_test-Funktion in mehrere Prozesse unterteilt, obwohl sie kurz ist.
polls.py
def form_test(request):
if request.method == "POST": #Verarbeitung beim Empfang per POST-Methode
form = MyForm(data=request.POST) #Formularerstellungsprozess (+Übergeben Sie die empfangenen Daten an Form)
if form.is_valid():
pass #Verarbeitung, wenn der Eingabewert des Formulars korrekt ist
else: #Verarbeitung beim Empfang durch die GET-Methode
form = MyForm() #Formularerstellungsprozess (keine Daten)
return render(request, 'polls/form.html', { #Vorlagen-Rendering
'form': form,
})
Es wurde mit Kommentaren durcheinander gebracht, aber zuallererst kann es grob unterteilt werden, ob es von "GET" oder "POST" aufgerufen wurde.
Im Fall von "GET" ist dies der Vorgang, bei dem die Seite zuerst angezeigt wird, sodass beim Erstellen des Formulars kein Argument vorlag.
Andererseits gibt es im Fall von "POST" einen Prozess zum Empfangen der Eingabedaten, nachdem die Seite einmal angezeigt wurde.
Data = request.POST wird als Argument von Form übergeben.
Darüber hinaus wird die Gültigkeit dieser Daten beurteilt (form.is_valid ()), und wenn sie korrekt sind, wird eine gewisse Verarbeitung durchgeführt.
In der von django bereitgestellten FormView-Klasse ist jeder dieser Prozesse eine Methode.
Sie können die Verarbeitung des relevanten Teils ändern, indem Sie eine bestimmte Methode überschreiben.
Das Folgende ist eine Liste von Methoden, die überschrieben werden sollen, wenn die Operation als Beispiel geändert wird.
(Es gibt andere Methoden in der Basisansicht (z. B. eine Methode, die get beim GET aufruft)).
Methoden, die in FormView überschrieben werden können
def get(self, request, *args, **kwargs): #Wird beim Zugriff mit der GET-Methode aufgerufen
def post(self, request, *args, **kwargs): #Wird beim Zugriff mit der POST-Methode aufgerufen
def put(self, *args, **kwargs): #Wird beim Zugriff mit der PUT-Methode aufgerufen
def get_initial(self): #Legen Sie den Anfangswert von Form fest
def get_prefix(self): #Formularpräfix festlegen
def get_form_class(self): #Holen Sie sich die Form-Klasse zu verwenden
def get_form_kwargs(self): #Ruft die Argumente ab, die an die Form-Klasse übergeben werden sollen
def get_form(self, form_class=None): #Ruft eine Instanz der Form-Klasse ab
def get_success_url(self): #URL, die nach erfolgreichem Abschluss umgeleitet werden soll
def form_valid(self, form): #Normale Verarbeitung
def form_invalid(self, form): #Was tun, wenn die Daten falsch sind?
def get_context_data(self, **kwargs): #Holen Sie sich den Kontext, der an die Vorlage übergeben werden soll
def render_to_response(self, context, **response_kwargs): #Erstellen Sie eine Antwort
def get_template_names(self): #Rufen Sie den Vorlagennamen ab, der zum Rendern verwendet wird
Es gibt Methoden namens "get_form_class" und "get_template_names", um die zu verwendende Formularklasse und Vorlage anzugeben.
Anstatt diese Methode zu überschreiben, funktioniert es, einfach Feldwerte wie "form_class" und "template_name" anzugeben.
Geben Sie für eine einfache Formularseite an, was Sie angeben
form_class: Zu verwendende Formularklasse
template_name: Vorlage, die zum Rendern verwendet wird
success_url: URL, zu der bei Erfolg gesprungen werden soll
Es gibt nur drei.
Darüber hinaus möchten Sie etwas für den Erfolg tun, damit Sie form_valid überschreiben.
success_url ist eine Zeichenkettenspezifikation. Wenn Sie den in url festgelegten Namen verwenden möchten, verwenden Sie den Resolver.
Sie können das Feld nicht mit resolve_url festlegen, wenn Sie die Klasse definieren. Verwenden Sie daher reverse_lazy oder
Es wird get_success_url überschreiben.
Der umgeschriebene form_testh lautet wie folgt.
polls/views.py
from django.views.generic import FormView
from django.core.urlresolvers import reverse_lazy
from .forms import MyForm
...
class FormTest(FormView):
form_class = MyForm
template_name = 'polls/form.html'
success_url = reverse_lazy('polls:index')
form_test = FormTest.as_view()
Löschen Sie den def form_test (request):, den Sie zuerst erstellt haben, weil er nicht notwendig ist.
Namenskonflikt und ein Fehler tritt auf.
Bei Verwendung einer klassenbasierten Ansicht wie der obigen Quelle
Führen Sie nach der Klassendefinition view name = class name.as_view () aus.
Die Funktion form_test, die ich zu Beginn geschrieben habe, enthielt if-Anweisungen für die Methodenbeurteilung und Datenbeurteilung.
Wenn Sie FormView verwenden, wird das Urteil in die Super-Klasse verschoben
Ich konnte eine Ansicht ohne if-Anweisung (= Logik) erstellen.
Umschreiben der Detailfunktion
Quelle → 1efe74c527
Zuletzt schreiben wir die Detailfunktion in eine klassenbasierte Ansicht um.
Erstens ist es kompliziert genug, um nicht für Tutorials geeignet zu sein.
Es gibt zwei Gründe
- Benötigen Sie eine Frage-Instanz in der Vorlage
- Erfordert eine
Question-Instanz als Argument für die Form-Klasse
Wenn es nur 1 ist, ist die Story einfach und es gibt eine Detailansicht, um die Detailseite einer Instanz anzuzeigen.
Die Anzeige wird vervollständigt, indem das Modell und die Vorlage angegeben werden, die in dieser Klasse verwendet werden sollen, genau wie bei FormView.
Natürlich können Sie den Namen des von \ # view (jetzt pk) empfangenen Arguments und den Namen des an die Vorlage übergebenen Objekts ändern.
\ # Außerdem wird standardmäßig (* Anwendungsname * / * Modellname * _detail.html) verwendet, auch wenn Sie keine Vorlage angeben.
Für Nr. 2 ist es außerdem einfach, die Argumente der Form-Klasse zu erhöhen (überschreiben Sie einfach "get_form_kwargs").
Die Tatsache, dass Sie eine "Frage" -Instanz benötigen, erschwert die Geschichte.
Da SingleObjectMixin als Mixin der View-Klasse vorbereitet wird, die eine Instanz eines bestimmten Modells erfasst,
Dieses Mal werden wir dieses Mixin und FormView in Kombination verwenden.
def detail(request, pk):
obj = get_object_or_404(Question, pk=pk)
if request.method == "POST":
form = VoteForm(question=obj, data=request.POST)
if form.is_valid():
form.vote()
return redirect('polls:results', pk)
else:
form = VoteForm(question=obj)
return render(request, 'polls/detail.html', {
'form': form,
'question': obj,
})
Detail vor dem Umschreiben
↓ Umschreiben mit Klasse
#### **`polls/views.py`**
```python
from django.shortcuts import resolve_url
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin
from .forms import VoteForm
from .models import Question
...
class Detail(SingleObjectMixin, FormView):
model = Question
form_class = VoteForm
context_object_name = 'question'
template_name = 'polls/detail.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super().post(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['question'] = self.object
return kwargs
def form_valid(self, form):
form.vote()
return super().form_valid(form)
def get_success_url(self):
return resolve_url('polls:results', self.kwargs['pk'])
detail = Detail.as_view()
Zunächst benötigen Sie eine Instanz von "Question" für "GET" und "POST".
self.object = self.get_object()
Ich versuche anzurufen.
Die mit dieser Methode zu erfassende Modellklasse wird durch model = Question angegeben.
Da wir eine "Frage" -Instanz mit dem Namen "Frage" in der Vorlage verwenden,
Der Name wird durch "context_object_name =" question "" angegeben.
Weil diese Instanz als Argument für "VoteForm" benötigt wird
Überschreiben von get_form_kwargs und Hinzufügen von question Argument.
Ich möchte abstimmen, wenn die Daten korrekt sind, also überschreibe form_valid und
Ich versuche form.vote aufzurufen.
Schließlich überschreiben wir get_success_url, um die Ziel-URL neu zu schreiben.
Da sich das von view empfangene Argument in "self.kwargs" befindet, wird das von der URL mit "self.kwargs [" pk "]" empfangene pk an die Ergebnis-URL übergeben.
"Es ist nicht viel einfacher als die erste" Detail "-Funktion, es fühlt sich komplizierter an, aber ist es in Ordnung, es zu einer Klasse zu machen?"
Diejenigen, die denken, dass sie das Wichtige vergessen haben.
Klassen werden ** geerbt und wiederverwendet **.
Wenn Sie eine andere View-Klasse mit dieser Klasse als Superklasse erstellen, genauso wie Sie die Detail-Klasse durch Erben von FormView erstellt haben
Wenn Sie eine Ansicht schreiben, die dieselbe Verarbeitung ausführt, können Sie einfach eine Ansicht erstellen, die denselben Vorgang ausführt, indem Sie einfach vier Felder wie "Modell" neu schreiben.
Wenn Sie eine Ansicht als Funktion schreiben, nutzen Sie diese Gelegenheit, um zu einer klassenbasierten Ansicht zu wechseln.
Als nächstes werden wir Bootstrap verwenden, um das Design zu bereinigen.
Zum nächsten Tutorial
→ Andere Tutorials