Python Django Tutorial (5)

Es ist ein Material für Lernsitzungen Dieses Mal werde ich Form etwas abseits des ursprünglichen Tutorials erklären. Bevor ich das Formular betrete, werde ich ein wenig über das Aktualisieren von Django und Namespace der URL einführen.

Tutorial Tutorial Tutorial 1 Tutorial 2 Tutorial 3 Tutorial 4

Andere Tutorials

Quelle (Github)

Außerdem habe ich bis zum letzten Mal django1.8 erklärt, aber seit django1.9 veröffentlicht wurde, während ich Updates übersprungen habe. In den folgenden Tutorials erklären wir Django 1.9. Selbst wenn Sie die Version von Django von 1.8 auf 1.9 ändern, gibt es keinen besonderen Unterschied im Inhalt der Tutorials 1 bis 4.

Migration zu Django 1.9 und Einführung von require.txt

Quelle → ee195d1

Django-Update

Sie können auf den neuesten Django (1.9.2 vom 20. Februar 2016) aktualisieren, indem Sie den folgenden Befehl in die Befehlszeile eingeben. Wenn Sie eine virtuelle Umgebung verwenden, vergessen Sie nicht, die virtuelle Umgebung mit "workon" zu aktivieren. (tutorial)$ pip install --upgrade django

(tutorial)$ pip install --upgrade django
Collecting django
  Using cached Django-1.9.2-py2.py3-none-any.whl
Installing collected packages: django
  Found existing installation: Django 1.8.6
    Uninstalling Django-1.8.6:
      Successfully uninstalled Django-1.8.6
Successfully installed django-1.9.2

Wenn es normal endet, wird der bereits installierte Django (in diesem Fall 1.8.6) wie oben beschrieben deinstalliert und der neueste Django installiert.

requirements.txt In diesem Tutorial ist Django die einzige externe Bibliothek, die bisher verwendet wurde, aber die Anzahl der in Zukunft verwendeten verwandten Bibliotheken wird stetig zunehmen. Welche Bibliothek benutzen Sie gerade? , Ist die Version der Bibliothek dieselbe? Es ist schwierig, jedes Mal zu überprüfen. Glücklicherweise hat Python ein Paketverwaltungssystem namens "pip" und eine virtuelle Umgebung namens "virtualenv". Sie werden nicht oft unter diesem Problem leiden.

Geben Sie den folgenden Befehl in die Shell ein, um eine Liste der in der aktuellen Umgebung verwendeten Bibliotheken abzurufen.

(tutorial)$ pip freeze
Django==1.9.2
wheel==0.24.0

Gemäß der Konvention in Python wird dieser Inhalt als "require.txt" ausgegeben. Eine andere Person kann die erforderlichen Bibliotheken durch Importieren dieser Datei installieren. Wie Sie sehen können, hat der Ausgabeinhalt auch eine Versionsnummer wie 1.9.2, sodass Sie sich keine Gedanken über Fehlfunktionen aufgrund unterschiedlicher Versionen machen müssen.

Ich wollte es in das Tutorial aufnehmen, habe es aber nicht erstellt, also habe ich es mit commit hinzugefügt: ee195d1.

Ausgabe der von Ihnen verwendeten Bibliothek (Erstellen der Anforderung.txt)

(tutorial)$ pip freeze > requirements.txt

Leiten Sie einfach den Inhalt von "pip freeze" um. Im Fall von Django wird empfohlen, es in dieselbe Hierarchie wie "manage.py" zu setzen.

Bibliothek importieren

Verwenden Sie zum Importieren den Befehl pip install -r. Nachdem Sie bestätigt haben, dass es sich in der Umgebung, die Sie importieren möchten, nach "-r" um "Workon" handelt Beschreiben Sie den Pfad zu der Datei, die Sie importieren möchten (require.txt).

(tutorial)$ pip install -r requirements.txt

Wenn Sie bereits eine Bibliothek installiert haben und deren Version aktualisieren möchten (tutorial)$ pip install -U -r requirements.txt Sie benötigen die Option -U wie>. Als ich es zur Hand versuchte, schien es jedoch, dass wenn die Pip-Version 8.0.2 ist, sie aktualisiert wird, ohne sie hinzuzufügen.

Fügen Sie der URL einen Namespace hinzu

Quelle → bba5e4f

In Tutorial 3 habe ich die Erklärung der URL-Namespace-Konvertierung übersprungen. In Anbetracht der Zukunft ist es zweckmäßig, sie zu trennen. Legen Sie daher den Namespace in der Umfrage-URL fest. Um es hinzuzufügen, fügen Sie einfach "Namespace" zum Argument der Funktion "include" hinzu.

tutorial/urls.py


urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^polls/', include('polls.urls')),
]

↓ Fügen Sie dem Include-Argument von Umfragen einen Namespace hinzu

tutorial/urls.py


urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^polls/', include('polls.urls', namespace='polls')),
]

Achten Sie darauf, die Position der schließenden Klammer nicht als Argument für die URL-Funktion zu verwechseln

Wenn Sie einen Namespace festlegen, können Sie eine URL in Form von "Namespace: hoge" abrufen. Der Namespace kann auch hierarchischer geschrieben werden, z. B. "api: polls: create". Ich habe das Präfix "poll_" zum Namen des Include-Ziels "polls / urls.py" hinzugefügt. Wenn Sie einen Namespace verwenden, ist dieser nicht erforderlich. Löschen Sie ihn daher.

polls/urls.py


urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'(?P<pk>\d+)/$', views.detail, name='poll_detail'),
    url(r'(?P<pk>\d+)/vote$', views.vote, name='poll_vote'),
    url(r'(?P<pk>\d+)/results$', views.results, name='poll_results'),
]

↓ Da der Namespace abgeschnitten ist, wird das Präfix "poll_" nicht mehr benötigt.

polls/urls.py


urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'(?P<pk>\d+)/$', views.detail, name='detail'),
    url(r'(?P<pk>\d+)/vote$', views.vote, name='vote'),
    url(r'(?P<pk>\d+)/results$', views.results, name='results'),
]

In django 1.9 schreiben Sie den Namespace-Namen nicht in das include-Argument in tutorial / urls.py Sie können es auch festlegen, indem Sie "app_name =" polls "in" polls / urls.py "schreiben. https://docs.djangoproject.com/en/1.9/releases/1.9/#passing-a-3-tuple-or-an-app-name-to-include

Mit dieser Änderung wird die URL nun vom Namen zu "polls: detail" anstelle von "poll_detail" gezogen. Bitte überprüfen Sie den Quellendifferenz für das korrigierte Teil.

Durch das Ausschneiden des Namespace wird die "Umfragen" -App stärker vom "Tutorial" -Projekt getrennt und ist in anderen Projekten einfacher zu verwenden. Wenn bei der vorherigen Methode eine andere Anwendung im selben Projekt der URL einen Namen wie "poll_detail" gibt, tritt ein Fehler auf. Sie müssen vorsichtig mit den URL-Namen aller vom Projekt verwalteten Anwendungen sein. Verwenden Sie andererseits den Namespace, um Konflikte mit dem Namespace in root urls.py (tutorial / urls.py) zu vermeiden. Du musst nur vorsichtig sein.

Was ist Form?

Kommen wir nun endlich zur Geschichte von Form. Das Formular wird verwendet, um Daten in einem bestimmten Format vom Client an den Server zu übergeben, wie die englische Übersetzung von "Formular, Antragsformular" bedeutet. In Tutorial 4 wurde das Formular direkt in die Vorlage geschrieben, und die Verarbeitung nach dem Empfang wurde auf der Ansichtsseite geschrieben. Die Vorlage und die Ansicht entsprechen jedoch der Ansicht und dem Controller im MVC-Modell, und es ist nicht gut, wenn die Logik hier enthalten ist. Im aktuellen Format wird auch die Anzeige des Optionsfelds in der Vorlage beschrieben und seine Validierung (Feststellung, ob die ausgewählten Daten korrekt sind). Weiterhin wird in der Ansicht die Verarbeitung (Voting-Verarbeitung) unter Verwendung des Eingabewerts beschrieben. Da jedoch die Eingabeelemente, die Validierung für sie und die Verarbeitung unter Verwendung der Daten eng miteinander verbunden sind. Ich möchte diese gemeinsam behandeln. Die Formularklasse wird in Django und allgemeinen Eingaben (Text, Auswahlliste, Optionsfeld usw.) und vorbereitet Wir stellen den Validator zur Verfügung (Eingabeprüfung).

Die Form-Klasse erleichtert das Schreiben von Tests für Honke Tutorial 5. Sie können die Anzahl der Eingabeelemente leicht erhöhen und sie an anderen Stellen problemlos wiederverwenden. Darüber hinaus kann durch die Verknüpfung mit der klassenbasierten Allzweckansicht die Beschreibung der Ansicht weiter reduziert und verständlicher gemacht werden.

Formularklasse

Textfeldausgabe

Quelle → 34698a1

Lassen Sie uns zunächst versuchen, ein Formular zu erstellen. Erstellen Sie im Anwendungsordner eine Datei mit dem Namen forms.py und definieren Sie die Form-Klasse darin. Legen Sie für die Form-Klasse die Feldklasse als Mitglied fest. Bitte beziehen Sie sich auf das offizielle Dokument für die Feldklasse, die eingestellt werden kann. https://docs.djangoproject.com/en/1.9/ref/forms/fields/

Lassen Sie uns vorerst CharField festlegen, ein Feld zur Eingabe von Zeichen. CharField muss die maximale Anzahl von Zeichen (max_length) als erforderliches Argument angeben. Legen Sie daher vorerst 100 Zeichen fest.

polls/forms.py


from django import forms


class MyForm(forms.Form):
    text = forms.CharField(max_length=100)

Lassen Sie uns die Ausgabe überprüfen, um zu sehen, was passiert, wenn wir dies schreiben. Starten Sie die Python-Shell mit der Shell "./manage.py", erstellen Sie eine Instanz der zuvor erstellten Form-Klasse und erstellen Sie sie. Lass es uns drucken.

$ ./manage.py shell
(InteractiveConsole)
>>> from polls.forms import MyForm
>>> f = MyForm()
>>> print(f)
<tr><th><label for="id_text">Text:</label></th><td><input id="id_text" maxlength="100" name="text" type="text" /></td></tr>

Sie können sehen, dass das Texttyp-Eingabe-Tag als Ausgabe ausgegeben wird. Da der Feldname auf "Text" gesetzt ist, können Sie auch bestätigen, dass die Zeichenfolge "Text" als Bezeichnung angezeigt wird.

Ausgabe in Vorlage, Bestätigung mit Browser

Quelle → 34f4914

Als nächstes erstellen wir die erstellte Formularklasse HTML. Schreiben Sie zunächst die Formularerstellung und übergeben Sie sie in views.py an die Vorlage.

polls/views.py


from .forms import MyForm


def form_test(request):
    form = MyForm()
    return render(request, 'polls/form.html', {
        'form': form,
    })

Als nächstes bereiten wir eine Vorlage vor. Da wir den Vorlagenpfad polls / form.html angegeben haben, ist der Speicherort der Datei Es ist polls / templates / polls / form.html.

polls/templates/polls/form.html


<html>
  <body>
    <form>
      {{ form }}
    </form>
  </body>
</html>

Jetzt sollte die folgende Zeichenfolge in der Shell in {{form}} bestätigt werden. <tr><th><label for="id_text">Text:</label></th><td><input id="id_text" maxlength="100" name="text" type="text" /></td></tr>

Verbinden Sie abschließend die Funktion form_test und die URL. Fügen wir eine URL zu polls / urls.py hinzu.

polls/urls.py


urlpatterns = [
...
    url(r'^form$', views.form_test),
...
]

Starten Sie nach dem bisherigen Schreiben den Testserver mit ./manage.py runserver und überprüfen Sie ihn mit einem Browser. Die URL lautet "http: // localhost: 8000 / polls / form".

Kobito.HyYPSO.png Bildschirm

Es ist eine mörderische Szene, aber vorerst kann man sehen, dass es eine Box für die Eingabe gibt.

Kobito.JxJa67.png HTML-Quelle

Die HTML-Quelle sieht so aus. Wie erwartet wurde der Teil {{form}} ersetzt.

POST-Übertragungsprozess

Quelle → 06c8422

Nun, das Eingabefeld wurde erstellt, aber auf der Serverseite gibt es noch keinen Empfangsprozess. Beschreiben Sie beim Senden von Daten an den Server mit HTML ** wo ** ** wie ** Daten im Tag

gesendet werden. Schreiben Sie die Attribute "Aktion" bzw. "Methode". Zum Senden müssen Sie außerdem die Schaltfläche "Senden" im Tag "" 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>

Kobito.1nDDdU.png 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.

Kobito.Ffr1Uf.png

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.

Kobito.Bgm3aT.png

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

Kobito.WXYnel.png

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>

Kobito.5NwxDg.png Ü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

Kobito.cya0WW.png

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>'

Kobito.j0CZTQ.png

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

  1. Benötigen Sie eine Frage-Instanz in der Vorlage
  2. 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

Recommended Posts