[PYTHON] Django tutorial summary for beginners by beginners ④ (Generic View)

Introduction

This article is a series of steps through Django's official tutorials. This time, we'll move on to the fourth article, "Creating your first Django app, part 4."

Django tutorial summary for beginners by beginners ① (project creation ~) Django tutorial summary for beginners by beginners ② (Model, Admin) Django tutorial summary for beginners by beginners ③ (View) Django tutorial summary for beginners by beginners ④ (Generic View) Django tutorial summary for beginners by beginners ⑤ (test) Django tutorial summary for beginners by beginners ⑥ (static file) Summary of Django tutorials for beginners by beginners ⑦ (Customize Admin)

Creating your first Django app, part 4

https://docs.djangoproject.com/ja/3.0/intro/tutorial04/

Write a minimal form Place the voting form in the detail.html created in the previous article.

polls/templates/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>

forloop.counter is a value that indicates how many times the loop of the for tag was executed. If you look at the contents, you can see that all the choices related to Question are displayed as radio button choices in the for statement.

It is necessary to insert {% csrf_token%} when creating a POST form for CSRF measures.

Then edit polls / views.py so that votes work well.

polls/views.py


from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls 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):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            '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=(question.id,)))

By request.POST ['choice'], the value POSTed by the name of'choice' in the above Form is read as selected_choice.

A KeyError is thrown when request.POST ['choice'] does not exist (ie, if the user does not select anything). In that case, the form will be rendered again with an error message.

When the process ends normally, it redirects to results. (Redirect should be applied when processing such as POST is completed normally (regardless of Django))

You can prevent URL hardcoating with the reverse function. The usage is similar to the URL specification used in ʻindex.html`.

Now, add the views of results to polls / views.py.

polls/views.py


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

The content is almost the same as the view of detail.

Let's also create a Template.

polls/templates/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>

Did you notice that there is one problem so far?

In the current processing flow, first get selected_choice from DB, calculate a new value from its votes and save it in DB.

Even if the value of votes was originally 42, if Mr. A and Mr. B vote at the same time, the place that should originally be 44 becomes 43.

It seems that such a problem is called a "conflict problem", and the following article will be helpful for the explanation of F () for solving it. All records until uncle Java can use Python (No. 16)

Use generic view: less code is good

Django has a shortcut called General View (generic view)

Retrieves data from the database according to the parameters passed via 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.

... apparently ...

Modify URLconf

Modify polls / urls.py as follows

polls/urls.py


from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    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:question_id>/vote/', views.vote, name='vote'),
]

The difference is that views.IndexView.as_view () etc. is passed to the view specified by path. Also, question_id has been renamed to pk. (The reason will be described later)

Create the ʻIndexView` class etc. in the view.

polls/views.py


from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from .models import Choice, Question


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        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):
    ... # same as above, no changes needed.

ListView and DetailView are used. The question_id was renamed as pk because it is specified as such in the DetailView.

By default, the DetailView generic view uses a template named / _detail.html, but you can change the template used by specifying thetemplate_nameattribute. (Same for ListView)

Recommended Posts

Django tutorial summary for beginners by beginners ④ (Generic View)
Django tutorial summary for beginners by beginners ③ (View)
Django tutorial summary for beginners by beginners ⑤ (test)
Django tutorial summary for beginners by beginners ⑦ (Customize Admin)
Django tutorial summary for beginners by beginners ⑥ (static file)
Django Tutorial Summary for Beginners by Beginners (Model, Admin)
Django tutorial summary for beginners by beginners ① (project creation ~)
Reference resource summary (for beginners)
[Explanation for beginners] TensorFlow tutorial MNIST (for beginners)
Machine learning summary by Python beginners
[For beginners] Django -Development environment construction-
What is scraping? [Summary for beginners]
TensorFlow Tutorial MNIST For ML Beginners
Django Girls Tutorial Summary First Half
Pandas basics summary link for beginners
[Deprecated] Chainer v1.24.0 Tutorial for beginners
TensorFlow Tutorial -MNIST For ML Beginners
[Explanation for beginners] TensorFlow tutorial Deep MNIST
[Linux command summary] Command list [Must-see for beginners]
Django Summary
Ajax in Django (using generic class view)
A textbook for beginners made by Python beginners
An introduction to object-oriented programming for beginners by beginners
About Nim higher-order functions for Nim beginners written by Nim beginners
Conducting the TensorFlow MNIST For ML Beginners Tutorial
Roadmap for beginners
Python Django Tutorial (5)
Python Django Tutorial (2)
Python tutorial summary
Django 1.9 for internationalization
django tutorial memo
Python Django Tutorial (8)
Python Django Tutorial (6)
Start Django Tutorial 1
Django class-based view
Django filter summary
Python Django Tutorial (7)
Python Django Tutorial (1)
Python Django tutorial tutorial
Python Django Tutorial (3)
Python Django Tutorial (4)
[Translation] NumPy Official Tutorial "NumPy: the absolute basics for beginners"
I tried the MNIST tutorial for beginners of tensorflow.
Summary of pre-processing practices for Python beginners (Pandas dataframe)
How to use bootstrap in Django generic class view
DJango Note: From the beginning (using a generic view)
[Linux] Basics of authority setting by chmod for beginners
How to upload files in Django generic class view
[For beginners] Django Frequently used commands and reference collection