English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Быстрый старт Django - форма

В предыдущем уроке мы介绍了 Вид Djangoи написали простую пример. В этом разделе мы изучим приложение для онлайн-голосования и сосредоточимся на простом обработке форм с минимальным количеством кода.

Напишем простую форму

Давайте обновим шаблон poll detail ("polls/detail.html") , из предыдущего урока, в шаблоне polls/templates/polls/detail.html содержится элемент HTML<form>:

# Имя файла : example.py
# Авторские права : 2020 By w3codebox
# Автор по : ru.oldtoolbag.com
# Дата : 2020-08-08
<h1>{{ question.question_text }}</h1>
 {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
 <form action="{% url 'polls:vote' question.id %}" method="post">
 {% csrf_token %}
 {% for choice in question.choice_set.all %}
     <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
     <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
 {% endfor %}
 <input type="submit" value="Vote" />
 </form> Шаблон, показанный выше, отображает выбор каждого вопроса с одним радио-кнопкой. Значение каждой радио-кнопки связано с идентификатором выбора вопроса. Имя каждой радио-кнопки — "choice". Это означает, что когда кто-то выбирает одну из радио-кнопок и отправляет форму, будет отправлено POST-данные choice=#, где # — это ID выбранного выбора. Это базовое понятие HTML-формы.  
  Мы устанавливаем действие формы {% url 'polls:vote' question.id %}, а также устанавливаем method="post". Использование method="post" (в сравнении с method="get") очень важно, потому что отправка этой формы изменяет поведение данных на сервере. При создании формы, которая изменяет данные на сервере, используйте method="post". Эта статья не только для Django; это хорошая практика веб-разработки.  
  forloop.counter показывает, через сколько раз был пройден цикл для этикеток формы  
  Поскольку мы создаем POST-форму (которая может изменить данные), нам нужно担心 фальшивые запросы от другого сайта. Но не стоит волноваться, потому что Django предоставляет очень удобную систему защиты. В общем, для всех POST-запросов на внутренние URL должны использоваться шаблонные теги {%csrf_token%}.

Мы создали виртуальное 实现 функции vote(). Теперь создадим полезную версию. Добавьте следующий код в файл polls/views.py:

polls/views.py файл содержит следующее:

# Имя файла : example.py
# Авторские права : 2020 By w3codebox
# Автор по : ru.oldtoolbag.com
# Дата : 2020-08-08
from django.shortcuts import get_object_or_404, render
 from django.http import HttpResponseRedirect, HttpResponse
 from django.core.urlresolvers import reverse
 from models import Choice, Question
 # ...
 def vote(request, question_id):
     question = get_object_or_404(Question, pk=question_id)
     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': "Вы не выбрали вариант.",
         )
     else:
         selected_choice.votes += 1
         selected_choice.save()
         # всегда возвращайте HttpResponseRedirect после успешного обработки
         # с данными POST. Это предотвращает отправку данных дважды, если пользователь
         # пользователь нажимает кнопку Возврат (Back button).
         return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

Этот код содержит несколько вещей, которые еще не были рассмотрены в этом руководстве:

request.POST является объектом, ähnlich einem Dictionary, который позволяет вам доступ к переданным данным через имя ключа. В этом случае request.POST['choice'] возвращает ID выбранного choice в виде строки. Значения request.POST всегда строки. 

Примечание: Django также предоставляет request.GET для доступа к данным GET тем же образом - но мы явно используем request.POST в нашем коде, чтобы убедиться, что данные могут быть изменены только через вызовы POST.

Если данные POST не содержат choice, request.POST['choice'] вызовет исключение KeyError. В приведенном выше коде проверяется исключение KeyError и отображается сообщение об ошибке для формы, если не указан choice.

После увеличения счетчика выбора, код возвращает HttpResponse с перенаправлением, а не обычный HttpResponse. HttpResponseRedirect требует параметра: URL, на который будет перенаправлен пользователь (см. ниже - как мы строим URL в этой ситуации).

Как указано в комментариях Python, всегда следует возвращать HttpResponse редиректа после успешной обработки POST данных.

В этом примере мы используем HttpResponseRedirect и функцию reverse(). Эта функция помогает избежать жесткой кодировки URL в видах. Потому что мы хотим управлять и указывать на URL-модели, переменные части которых можно изменить через имя вида. В этом случае использование URLconf конфигурации возвращает строку, такую как:

# Имя файла : example.py
# Авторские права : 2020 By w3codebox
# Автор по : ru.oldtoolbag.com
# Дата : 2020-08-08
"/polls/3/results/"

其中 3 — это значение question.id. Затем этот редирект URL вызовет последнюю страницу, отображаемую в функции просмотра results.

Теперь, если открыть адрес: http://127.0.0.1:8000/polls/1/, вы получите результат, как показано ниже:   Когда кто-то голосует за вопрос, функция просмотра vote() редиректит к странице результатов вопроса. Давайте напишем этот вид (polls/views.py):

# Имя файла : example.py
# Авторские права : 2020 By w3codebox
# Автор по : ru.oldtoolbag.com
# Дата : 2020-08-08
from django.shortcuts import get_object_or_404, render
 def results(request, question_id):
     question = get_object_or_404(Question, pk=question_id)
     return render(request, 'polls/results.html', {'question': question})),

Теперь, создайте шаблон polls/results.html (polls/templates/polls/results.html):

# Имя файла : example.py
# Авторские права : 2020 By w3codebox
# Автор по : ru.oldtoolbag.com
# Дата : 2020-08-08
<h2>{{ question.question_text }}</h2>
 <ul>
 {% for choice in question.choice_set.all %}
     <li>{{ choice.choice_text }} -- {{ choice.votes }} голос{{ choice.votes|pluralize }}</li>
 {% endfor %}
 </ul>
 <a href="{% url 'polls:detail' question.id %}">Голосовать снова?</a>

Теперь откройте в браузере /polls/1/ и проголосуйте за вопрос. Результаты должны обновляться каждый раз при голосовании. Если вы отправите форму, не выбрав вариант, вам покажут сообщение об ошибке. После выбора варианта и отправки формы вы увидите следующий результат:  

Использование общих видов: меньше кода - лучше

Изменить конфигурацию URL

Сначала откройте polls/urls.py и измените следующим образом:

from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
    url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]