Nice to meet you, everyone. I'm going to publish a memorandum of the process of creating a voting (poll) application using Django. Since I am a beginner of Qiita, please understand that some parts may be difficult to read.
series
-[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-No. 0- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 1- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 2- -[Beginner] [Python / Django] A fledgling web engineer tried a Django tutorial-Part 3-
I will write the form in HTML.
Description of form tag
--action: URL to send data --method: Data transmission method (get, post)
Description of input tag
--type: Radio button (radio), submit button (submit) --value: current value --id: ID that identifies the button
"{% Csrf_token%}" is a cross-site request forgery countermeasure mechanism provided by Django. Since we are using the POST method, we will use csrf_token.
polls/template/polls/detail.html
<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>
Access the POST data choice with "request.POST ['choice']". Returns KeyError if there is no choice in the POST data
If an exception occurs, the question form will be displayed again with an error.
"Reverse ('polls: results', args = (question.id))" returns polls / urls.py> path function (name ='results').
:polls/views.py
from django.http import HttpResponse, Http404, HttpResponseRedirect
from .models import Question, Choice
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
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': "You didn't select a choice."})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
It is OK if you access "http://127.0.0.1:8000/polls/
polls/template/polls/results.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
<ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
polls/views.py
from django.http import Http404, HttpResponseRedirect
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
Select an option on the "http://127.0.0.1:8000/polls/
We will continue to reduce the code. In particular, we will eliminate redundant parts.
These views represent the general case of basic web development. That is, it retrieves data from the database according to the parameters passed through the URL, loads the template, and returns the rendered template. This is so common that Django offers a shortcut called the generic view. A generic view is an abstraction of a common pattern that allows you to write an application without even writing Python code.
Only name = detail and results should be changed from "<int: questioniopkn_id>" to "<int: pk>". This is because it uses the DetailView, which will be explained later. name = index, detail, results will create a class later, so let's say "views. ** View.as_view ()"
polls/urls.py
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:questiopkn_id>/vote/', views.vote, name='vote'),
views.py changes a lot. I used to use functions a lot in def, but I use class.
--ListView The generic view uses the "
--DetailView The general view uses the "
polls/views.py
# Create your views here.
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.views import generic
from .models import Question, Choice
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
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': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
That's all for today. Thank you very much.
Recommended Posts