Learning history for participating in team app development in Python ~ Django Tutorial 4 ~

Introduction

We'll continue with the Django tutorial from the last time (https://qiita.com/shitikakei/items/753ba603b5bca272c69c). This time around, class-based views are an important part of using Django.

About the form


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


For example, suppose you want to create a form like this. It is a form that prepares an answer with a radio button for a certain question, checks it, and sends it by POST. {{forloop.counter}} is the number of loops for {% for choice in question.choice_set.all%}. The actual notation would be, for example, <input type =" radio "name =" choice "id =" choice1 "value =" 1 ">. Let's take a look at the view for this.

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

        #The above code causes conflict problems, so F(Column name)Use the method.
        selected_choice.votes = F('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,)))


What has changed compared to the previous time is that the HttpResposeRedirect and reverse objects have been imported. The former is a method for redirecting, and the latter reverse () method is a method that returns a URL and calls the URL from the named path set in urls.py. For example, in the above case The URL / polls / results is returned, but you can return the URL / polls / 1 / results by specifying question.id as an argument.

If you understand the contents of the vote function itself up to the last time, it is not so difficult to understand what you are doing. First, assign an instance to the variable. Since it is a get_object_or_404 method, it is an instance of the corresponding primary key data from the Question model. Exception handling it with the try-catch-else pattern. First, based on the POST data sent from the form, get the data from the database with the get () method. request.POST allows you to access the data sent with the specified key. For example, in this case request.POST ['choice'], it means to access the data whose name attribute is choice.


<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">

It will be this part.

So, this time it is a form with a radio button, so there are some choices in the for loop, but since there is only one data to be sent, the value of the choice's value is taken out and made into pk. Become. By the way, if there are multiple same name attributes in checkboxes etc., please get them withgetlist ()instead ofget (). Quiet talk, for example, question.choice_set.get (pk = request.POST ['choice']) becomes question.choice_set.get (pk = 1), that is, data with primary key 1 is choice It will be searched from the model and assigned to the variable as an instance. If it can be obtained safely, it will jump to ʻelse, if it cannot be obtained, it will be treated as an exception of KeyError, and the error message will be returned by the render () method and returned to the form screen. The process of ʻelse is to increase the number of votes, update it to the database, and redirect to the vote result screen. Now let's create a template for voting results.


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


The vote {{choice.votes | pluralize}} part is the expression that if the value to the left of pluiralize is plural, it returns a suffix that represents the plural. For example, in this case, if choice.votes is 2, then vote becomes votes.

Generic view (class-based view)

By the way, I've written various views (controllers) so far, but Django has a built-in so-called general-purpose view called a class-based view. view has the role of bridging data and ʻURL` to the template, but even though it has come so far

-Create and display a list with filter () -Obtain data from the database and reflect it in the template · Display one of many pages like polls / 1 / results

I think that such a process came out many times and I wrote view each time. A general-purpose view is a system that sets appropriate default values according to the model and form in advance so that you do not have to write such processing many times. By the way, as you can see from the fact that it is class-based, the generic view in Django is provided by the class. It seems that there is also a function base. Let's take a look at the previous view.


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

# Create your views here.
def index(request):
	latest_question_list = Question.objects.order_by('-pub_date')[:5]
	context = {
		'latest_question_list': latest_question_list,
	}
    return render(request, 'polls/index.html', context)

def detail(request, question_id):

	question = get_object_or_404(Question, pk=question_id)
	return render(request, 'polls/detail.html', {'question': question})

def results(request, question_id):
	response = "You`re looking at the results of question %s."
	return HttpResponse(response % question_id)

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 = F('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,)))

Next, here is the new view to write


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

from .models import Question, Choice

# Create your views here.
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:
		#Access POST data. This time, the ID of the option selected by the radio button of the form is returned as a character string and assigned to the variable.
		selected_choice = question.choice_set.get(pk=request.POST['choice'])
	#Specify the Key error in the exception specification. Exception handling if there is no 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 = F('votes') + 1
		selected_choice.save()
		#Redirect processing in Django. reverse()In urls.Call the URL from the named path set in py. You can specify a specific page by specifying the argument.
		return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

You can see that it is quite different. First, import the generic object from the django.views module. It can also be imported and used for each class-based view, such as from django.views.generic import ListView. In that case, the argument would be ListView instead of generic.ListView. And as mentioned above, since it is a class-based view, we will rewrite what was written as a function into a class and inherit each class-based view and use it. For example, it's a part like class IndexView (generic.ListView):. Since it inherits, specify the general-purpose view you want to use as an argument. Of course, inheriting can also be overridden. Let's look at each one.

Listview

Listview is a view for displaying a list of objects. In other words, it can be used when creating a list page.


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]

When you actually use it, it will be written as above. Normally, it is essential to specify the model when using a class-based view, but you can also specify the method of queryset (). For example, in the above, instead of simply displaying the list of models, we want to display the list in increments of 5, so we are specifying with query set () instead of specifying the model. After that, specify the template of the bridging destination with template_name, and decide the variable name of the object at the bridging destination with context_object_name. Aside from the former, I have to decide the latter

{% for question in latest_question_list %}

Where I was writing like this

{% for question in object_list %}

If you do not write it, it will not work. It goes without saying which one is easier to understand at first glance. By the way, by using a mechanism called Context Processor, you can define a template variable in a separate file and import it so that you do not have to specify it individually here. It can also be used like a global variable in a template. Reference: Introducing Google Analytics to Django

DetailView

DetailView is a class-based view that can be used for individual detail pages. The view you want to use for pages like polls / 1 / detail.


class DetailView(generic.DetailView):

	model = Question
	template_name = 'polls/detail.html'

You can see that we are specifying the model and the template. In addition to this, you have to specify pk or slug in ʻurls.py, but this time, specify pk` after this.

These are the two class-based views used in this tutorial, but there are several others, so this time we'll just take a quick look at what they have.

generic.base.View

This is the main class of class-based view. Each class base inherits this, and by inheriting it, we are using the class base.

Example of use



from django.http import HttpResponse
from django.views import View

class MyView(View):

    def get(self, request, *args, **kwargs):
        return HttpResponse('Hello, World!')

generic.edit.FormView and generic.edit.CreateView and generic.edit.UpdateView

Both can be used for forms, resulting in views with update processing. The role of FormView is to display the form when it receives the HTTP method GET, that is, to display the form when the ʻURL set in pathis hit. Then, when you receive theHTTP method POST, you can execute the process based on the requestreceived from the form. It seems to be used for forms that perform redirect processing without additional database processing, For example, the login form given as an example has a separate view called the authentication view calledLoginView`, so it seems that the latter, which will be described later, is often used.

Example of use



from django import forms

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

    def send_email(self):
        # send email using the self.cleaned_data dictionary
        pass

Regarding CreateView, the ʻinsert process is executed for the specified model based on the requestreceived from the form when theHTTP method POST` is received. In other words, it can be used for forms that add new records (data).

Example of use



from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = ['name']

ʻUpdateView` is not an addition, but a view used for forms that involve updating existing records.

Example of use



from django.views.generic.edit import UpdateView
from myapp.models import Author

class AuthorUpdate(UpdateView):
    model = Author
    fields = ['name']
    template_name_suffix = '_update_form'

Now you can see that the fields variables are defined in ʻUpdateView and CreateView. This is an item that must be set when using both views, and data input from the form will be ignored except for the specified fields. In other words, in the above example, no matter how many input items in the form correspond to, for example, ʻaddress or Tel, only the name field will be added / updated. This specification can be set in a list or tuple, so you can specify more than one.

Modify URLconf

Now that we've briefly covered the roles for each class base and confirmed how to define them, the next step is to modify ʻurls.py` so that it can use a generic view.


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'),

]

Earlier, you had to specify pk to use DetailView. Make sure that <int: question_id> is now <int: pk>.

views.py settings

Finally, modify views.py as described at the beginning of this item.


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

from .models import Question, Choice

# Create your views here.
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:
		#Access POST data. This time, the ID of the option selected by the radio button of the form is returned as a character string and assigned to the variable.
		selected_choice = question.choice_set.get(pk=request.POST['choice'])
	#Specify the Key error in the exception specification. Exception handling if there is no 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 = F('votes') + 1
		selected_choice.save()
		#Redirect processing in Django. reverse()In urls.Call the URL from the named path set in py. You can specify a specific page by specifying the argument.
		return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

Finally

I felt that understanding here is inevitable when dealing with Django.

reference

Introducing Google Analytics to Django Introduction to class-based generic views in Django and sample usage Collect Django's generic class views and mention the implementation

Recommended Posts

Learning history for participating in team app development in Python ~ Django Tutorial 5 ~
Learning history for participating in team app development in Python ~ Django Tutorial 4 ~
Learning history for participating in team app development in Python ~ Django Tutorial 1, 2, 3 ~
Learning history for participating in team app development in Python ~ Django Tutorial 6 ~
Learning history for participating in team app development in Python ~ Django Tutorial 7 ~
Learning history for participating in team application development in Python ~ Index page ~
Learning history for participating in team application development in Python ~ Think a little about requirement definition ~
Learning history for participating in team application development in Python ~ Supplement of basic items and construction of jupyterLab environment ~
Learning history to participate in team application development with Python ~ Build Docker / Django / Nginx / MariaDB environment ~
Learning history to participate in team application development in Python ~ After finishing "Introduction to Python 3" of paiza learning ~
Python Django Tutorial (5)
Python Django Tutorial (2)
Python Django Tutorial (8)
Python Django Tutorial (6)
Python Django Tutorial (7)
Python Django Tutorial (1)
Python Django tutorial tutorial
Python Django Tutorial (3)
Python Django Tutorial (4)
Boost.NumPy Tutorial for Extending Python in C ++ (Practice)
[Implementation for learning] Implement Stratified Sampling in Python (1)
Learning notes for the migrations feature in the Django framework (2)
Python Django tutorial summary
Build an interactive environment for machine learning in Python
Directory structure for test-driven development using pytest in python
App development to tweet in Python from Visual Studio 2017
Learning notes for the migrations feature in the Django framework (3)
Learning notes for the migrations feature in the Django framework (1)
Deep Learning Experienced in Python Chapter 2 (Materials for Journals)
Framework development in Python
Development environment in Python
AWS SDK for Python (Boto3) development in Visual Studio 2017
Slackbot development in Python
Tutorial for doing Test Driven Development (TDD) in Flask-2 Decorators
Building a development environment for Android apps-creating Android apps in Python
Tutorial for doing Test Driven Development (TDD) in Flask ―― 1 Test Client
Learning flow for Python beginners
Python learning plan for AI learning
Search for strings in Python
Techniques for sorting in Python
Python development in Visual Studio 2017
Qt for Python app self-update
Python Django Tutorial Cheat Sheet
Checkio's recommendation for learning Python
[For organizing] Python development environment
Python development in Visual Studio
About "for _ in range ():" in python
How about Anaconda for building a machine learning environment in Python?
Automatically resize screenshots for the App Store for each screen in Python
EEG analysis in Python: Python MNE tutorial
Implement stacking learning in Python [Kaggle]
Check for memory leaks in Python
Check for external commands in python
Web teaching materials for learning Python
Web application development memo in python
[For beginners] Django -Development environment construction-
Widrow-Hoff learning rules implemented in Python
Python development environment options for May 2020
<For beginners> python library <For machine learning>
Emacs settings for Python development environment
Python: Preprocessing in Machine Learning: Overview