Начинаем работу с Django — подключаем формы

Использование форм позволяет передавать информацию от пользователя на сервер.

Добавляем простую форму в 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.

Простая HTML форма

Для передачи данных выбран 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/ выведет результаты голосования.

Страница результатов

Таким образом наше приложение полностью функционально :)

Начинаем работу с Django — подключаем формы: 4 комментария

  1. Интересен момент, вроде всё делаю нормально…

    Вот такую ошибку выдаёт:
    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

    1. Leo, ошибка «invalid literal for int() with base 10» обычно означает, что int() получает строку, содержащую не целое число, а число с плавающей точкой.

      Приведенный пример генерирует url для перехода в форме и параметры, которые передаются автоматически, поэтому переходить вручную на адрес /polls/(любое_число)/vote/ нет нужды, это делается в процессе голосования.

      Опишите детальнее, на каком этапе возникает ошибка и приведите вашу view с названием vote — постараюсь подсказать.

      1. Проблема была в polls/urls.py
        Только уже не скажу где именно… когда сохранил закрыл и всё заработало…
        Тоесть просто скопировал с урока… Видимо машинальную ошибку допустил, когда спечатывал…

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *