Использование форм позволяет передавать информацию от пользователя на сервер.
Добавляем простую форму в HTML шаблон
Давайте изменим шаблон и создадим простую форму, которая позволит нам выбрать один из вариантов ответов.
<h1>{{ poll.question }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' poll.id %}" method="post"> {% csrf_token %} {% for choice in poll.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>
Приведенный шаблон сгенерирует форму, которая будет включать radio button для выбора одного варианта ответа. Значением выбранного пункта станет ID соответствующего варианта ответа. Форма передаст результат выбора используя метод POST.
Для передачи данных выбран method="post" поскольку после отправки происходит изменение данных на стороне сервера.
Счетчик forloop.counter равен текущей итерации цикла.
Поскольку данная форма меняет данные на сервере, нужно исключить возможность обращений напрямую с других сайтов. Для этого в Django предусмотрен {% csrf_token %}.
Данные, которые форма передаст на сервер, нужно обработать. Для этого мы предусмотрели view vote на предыдущем шаге.
Для обработки данных, замените заглушку в файле polls/views.py и импортируемые функции:
from django.shortcuts import get_object_or_404, render from django.http import HttpResponseRedirect, HttpResponse from django.core.urlresolvers import reverse from polls.models import Choice, Poll # ... def vote(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) try: selected_choice = p.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # Redisplay the poll voting form. return render(request, 'polls/detail.html', { 'poll': p, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() # Always return an HttpResponseRedirect after successfully dealing # with POST data. This prevents data from being posted twice if a # user hits the Back button. return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))
Теперь функция vote обрабатывает request.POST, который позволяет получить значения параметров, переданных при запросе. request.POST['choice'] возвращает ID выбранного варианта ответа в виде строки — все значения request.POST получаются в виде строки. Если вам нужно обработать параметры, переданные с помощью GET, используйте request.GET.
Если в запросе не окажется данных, при обращении к request.POST['choice'] будет вызвана ошибка KeyError. Приведенный код проверяет возникновение ошибки и возвращает форму, если значение не было получено.
При получении правильного значения, производится переадресация на страницу с результатом голосования, используя HttpResponseRedirect. После изменения данных всегда нужно делать переадресацию, чтобы избежать повторного изменения данных при обновлении страницы.
Теперь давайте выведем реальные результаты. Для этого замените код функции results:
def results(request, poll_id): poll = get_object_or_404(Poll, pk=poll_id) return render(request, 'polls/results.html', {'poll': poll})
Также нам понадобится HTML шаблон. Создайте файл polls/results.html:
<h1>{{ poll.question }}</h1> <ul> {% for choice in poll.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' poll.id %}">Vote again?</a>
Теперь при запросе /polls/1/ браузер позволяет выбрать вариант ответа, а /polls/1/results/ выведет результаты голосования.
Таким образом наше приложение полностью функционально :)
Интересен момент, вроде всё делаю нормально…
Вот такую ошибку выдаёт:
ValueError at /polls/(любое_число)/vote/
invalid literal for int() with base 10: »
И в пояснении написано:
/polls/views.py in vote
selected_choice = p.choice_set.get(pk=request.POST[‘choice’])
p
poll_id
‘(любое_число)’
request
я тот ещё археолог =)
Leo, ошибка «invalid literal for int() with base 10» обычно означает, что int() получает строку, содержащую не целое число, а число с плавающей точкой.
Приведенный пример генерирует url для перехода в форме и параметры, которые передаются автоматически, поэтому переходить вручную на адрес /polls/(любое_число)/vote/ нет нужды, это делается в процессе голосования.
Опишите детальнее, на каком этапе возникает ошибка и приведите вашу view с названием vote — постараюсь подсказать.
Проблема была в polls/urls.py
Только уже не скажу где именно… когда сохранил закрыл и всё заработало…
Тоесть просто скопировал с урока… Видимо машинальную ошибку допустил, когда спечатывал…