Learning history for participating in team app development in Python ~ Django Tutorial 1, 2, 3 ~

Introduction

Last time, I created a Django environment with Docker and tried it easily, so this time I will dig a little deeper into Django through the official tutorial while also serving as a supplement to the previous time. This time, I'm PU from 1 to 3 of the tutorial, where I personally felt it was important.

Django Tutorial

About include ().

ʻInclude () is a function that represents a reference to a URLconf (here url.py). Set the path with ʻurls.py in the argument and the name of ʻurl.py to be referenced in the second argument. Since we want to refer to polls' ʻurls.py here, we will set polls.urls.

You can set four arguments for path (): route, view, kwargs, and name. route will be the route address for that application. view specifies the view function you want to call. kwargs can pass any keyword as a dictionary to view, it is optional. name is a global URL that can be referenced from anywhere in Django if you specify it in ʻURL`.

Let's look at these two examples.


path('polls/', include('polls.urls'))


For example, in this description, route becomes the part of'polls /', and view becomes include ('polls.urls'). Was there a view in ʻinclude ('polls.urls')? If you think so, take a look at ʻurls.py again. You can see that it is imported at the beginning.

By the way, view in the second argument can also take the output of ʻas_views in addition to ʻinclude () like this time. ʻAs_views is a class only methodthat creates a function that meets the view criteria in Django. For more information, see [Reference article](https://qiita.com/tell-k/items/38c0612a44497b311d6b) and the documentation, but when you chew it, Django first determines the request method called thedispatch` method and that request method. I have a method that executes a method with the same name as. In this case, for example, from the previous article




class SampleView(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'app_folder/page01.html')

    def post(self, request, *args, **kwargs):
     	input_data = request.POST['input_data']
     	result = SampleDB.objects.filter(sample1=input_data)
     	result_sample1 = result[0].sample1
     	result_sample2 = result[0].sample2
     	context={'result_sample1':result_sample1, 'result_sample2':result_sample2}
     	return render(request, 'app_folder/page02.html', context=context,)

top_page = SampleView.as_view()


In this part, if request.method =='GET' is here, SampleView.get () will be executed. ʻAs_view is instantiated as cls(when it becomes an instance of a class method, the class itself is represented bycls instead of self) and creates a function that executes this dispatchmethod. Will bereturn, which means that it can be taken as an argument because it is classified as view`.

Well, what is name?


urlpatterns = [
	path('', views.index, name='index')

]


It's this kind of guy. By doing this, you can make the process that views.index is called when you hit the URL in the form of root index / index or root index /. There will be a more straightforward way to use it towards the end, so for now just remember that the path is named.

Relationships in Django



from django.db import models

# Create your models here.

class Question(models.Model):
	question_next = models.CharField(max_length=200)
	pub_date = models.DateTimeField('date published')

class Choice(models.Model):
	question = models.Foreignkey(Question, on_delete=models.CASCADE) #relation
	choice_text = models.CharField(max_length=200)
	votes = models.IntegerField(default=0)

Set in the form of models.Foreignkey (class name of the table to be related, on_delete = models.CASCADE). In this case, the relationship is Question: Choice = 1: multiple. To put it simply, there are multiple answers to one question.

ʻOn_deleteThe following sets whether to delete the object associated with it when the referenced object is deleted, or to keep it. In the case ofCASCADE`, it means that all the associated objects are deleted. For example

# polls_question

id		question_next

0		What`s_up?



# polls_choice


id		choice_text		votes		question_id
0		I`m_heading		 0				0
1		Stomachache		 1				1


Suppose you have a table like this. Here, the data of ʻid = 0in thepolls_question table is deleted, and the data of ʻid = 0 and ʻid = 1in thepolls_choicetable that refers to it is also deleted. It will be. This is the data deletion process whenCASCADEis specified. There are other options, but it seems that I often useCASCADE`. Since it is a little difficult to handle the data in the relation, I interpret that it is better to delete all the data in both tables that are dependent on each other when deleting one. Of course, you can specify that the other is treated as null, or that only the other is completely deleted.

Migration and API operations in Django (interaction with database)

Well, if you finish up to this point, you can complete the table by migrating with migrate, but since there is a command that outputs SQL statement and shows what migrate is doing, I will try it. ..

python manage.py makemigrations polls

In the case of docker, use the docker exec command to enter the container, move to the directory containing the manage.py file, and execute it. You can save the migrations for that application by specifying the name of the application folder in the makemigrations command. For example, if you execute this command this time

Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice


Thus the name 0001 is given to the migration and the file is saved. By the way, this time I made a mistake in migrating, and I made a mistake in the properties of the data registered in the table, so I changed it and did make migrations again.

In that case, the following file 0002_auto_20200408_1848.py will be created and the table will be updated when migrate again.

0002_auto_20200408_1848.py



# Generated by Django 3.0 on 2020-04-08 18:48

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('polls', '0001_initial'),
    ]

    operations = [
        migrations.RenameField(
            model_name='question',
            old_name='question_next',
            new_name='question_text',
        ),
    ]


Next, let's see what happens when this migration is migrate.

 py manage.py sqlmigrate polls 0001

If you specify the application folder and migration in the sqlmigrate command like this,

--
-- Create model Question
--
CREATE TABLE `polls_question` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `question_next` varchar(200) NOT NULL, `pub_date` datetime(6) NOT NULL);
--
-- Create model Choice
--
CREATE TABLE `polls_choice` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `choice_text` varchar(200) NOT NULL, `votes` integer NOT NULL, `question_id` integer NOT NULL);
ALTER TABLE `polls_choice` ADD CONSTRAINT `polls_choice_question_id_c5b4b260_fk_polls_question_id` FOREIGN KEY (`question_id`) REFERENCES `polls_question` (`id`);


The SQL statement is displayed like this, and you can see what the migrate command is doing. It's easy to see what kind of SQL statement is used to create a table. After checking so far, let's make a table by migrate.

Let's try the shell command as per the tutorial and interact with the database.

#Import the model and get the class
>>> from polls.models import Choice, Question  # Import the model classes we just wrote.

#Get all objects of Question class. Since there is no data, the result is empty.
>>> Question.objects.all()
OUT:<QuerySet []>

#To use the datetime module, django.Import the timezone class in it from utils.
>>> from django.utils import timezone

#Assign data to variables in the form of objects
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

#Save data
>>> q.save()

#Get data properties
>>> q.id
1

>>> q.question_text
"What's new?"

>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)


#Try to change properties
>>> q.question_text = "What's up?"
>>> q.save()

#Failure
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

Rewrite models.py to avoid failure.

import datetime
from django.db import models
from django.utils import timezone

# Create your models here.

class Question(models.Model):
	question_text = models.CharField(max_length=200)
	pub_date = models.DateTimeField('date published')

	#Add 1
	def __str__(self):
		return self.question_text

	#Add 2
	def was_published_recently(self):
		return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

class Choice(models.Model):
	question = models.ForeignKey(Question, on_delete=models.CASCADE)
	choice_text = models.CharField(max_length=200)
	votes = models.IntegerField(default=0)

	#Add 3
	def __str__(self):
		return self.choice_text

__str__ () is an object method. For example, here it is responsible for setting self as an argument to instrument the class and make each property human readable. The reason the object didn't display well in Question.objects.all () earlier is that the object remained machine readable. In other words, the object looks like an object of this class to our eyes as it is, so we will give it a name.

Addition 2 is the original method. Since it is a mathematical expression after return, it will return True or False. Since timezone.now () is the current date and datetime.timedelta (days = 1) is one day later, today--tomorrow is yesterday, and more than that, self.pub_date is true. .. In other words, it's a method that returns True if the data in the Question table was created after yesterday. However, as it is, there is a bug that True is returned even if it is a so-called future date. The Question table means registering the content of the question, but asking a question must always be past or present in terms of time. You asked yesterday, you said you asked today, but you didn't say you asked tomorrow, right? This bug seems to be fixed in the items after 4 of the tutorial, so I will leave it as it is for the time being.

Now, run the shell command again.


>>> from polls.models import Choice, Question

# __str__Since I added the method, question of Question property_text is called as the name of the object.

>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

#Confirm that you can narrow down the objects by id with the filter method.

>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>

#Question in the same way_Try to narrow down the objects whose text starts with what.
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

#Get objects added this year

>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>



# id=Error because the data of 2 does not exist
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.


#Get an object with a primary key of 1. Usually the primary key is id. So here pk=1 == id=Become 1
>>> Question.objects.get(pk=1)
<Question: What's up?>

#Check the operation of the additional 2 methods

>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True


#Instantiate an object with a primary key of 1.
>>> q = Question.objects.get(pk=1)

#Call the choice object associated with the above objects. The point is how many answers to the question. Since there is no data in the Choice table, it is returned empty.
>>> q.choice_set.all()
<QuerySet []>

# Question.objects.get(pk=1)As an answer linked to, add three data to the choice table.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

#The question property is the foreign key of the Choice table, that is, the primary key reference of the Question table.
>>> c.question

#Therefore, as mentioned above, the c variable is q= Question.objects.get(pk=1)Since it is tied to, the following result is returned.
<Question: What's up?>

# q = Question.objects.get(pk=1)Call the Choice object associated with and count the number of objects
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

#Among the Choice objects, narrow down the objects whose question creation date associated with the primary key of the referenced Question table is this year.

>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

#Delete a specific Choice object.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()



Let's take a closer look at the role of URLconf through views.py.

polls/views.py



from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .models import Question

# 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):

	"""
	try:
		question = Question.objects.get(pk=question_id)
	except Question.DoesNotExist:
		raise Http404("Question does not exist")
	return render(request, 'polls/detaill.html', {'question': question})

	"""

	#The above is a Django shortcut. get_object_or_404 method

	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):
	return HttpResponse("You`re voting on question %s." question_id)




polls/urls.py




from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
	path('', views.index, name='index'),
	path('<int:question_id>/', views.detail, name='detail'),
	path('<int:question_id>/results/', views.results, name='results'),
	path('<int:question_id>/vote/', vies.vote, name='vote'),

]


I mentioned path () earlier. For example, suppose you have access to / polls / 34 / here. Do you remember what happens with the above settings? The correct answer is to refer to ʻurl patterns in ʻurls.py to determine which view function to send the request to, and then execute the view function called there.

Let's dig a little deeper. First, look at the part specified in the first argument of path (). I did earlier that the root address is entered in this part. For example, the first description is easy to understand. In this way, the URL pattern specified here is / polls /. In other words, you can see that polls / is automatically specified even if the first argument is empty. (If not specified, an error will occur.) This means that when Django receives a request, it first loads the ʻurls.py file specified in ROOT_URLCONFofsettings.py. This is a file that designs the URL of the entire system. In the previous example, that is project / project / urls.py`. Let's say there is such a description there.



urlpatterns = [
	#URL to access the management site
    path('admin/', admin.site.urls),
    #URL to access the application "app" created this time
    path('app/', include('app.urls')),
    #If you do not specify any URL
    path('', views.index, name='index'),
    path('polls/', include('polls.urls')),
]


Some people may have already understood the mechanism when they came to this point. Think of the first path () part as a spell. The third description is the same as before. Of note are the second and fourth descriptions. By writing like this here, you can refer to ʻurls.py of each application, and you can match the request with the variable ʻurl patterns. Also, if you write path ('polls /', include ('polls.urls')) here, there is a request such as / polls / 34 / in polls / url.py. , It is already judged that polls matches, and it is judged which path () the other part matches. In that case, / polls / 34 / will not match the first path () of polls / url.py.

Then, what happens with the second and subsequent descriptions, let's look at <int: question_id>. This means looking for ʻintin the URL pattern and naming itquestion_id`.

From the document

With angle brackets, part of the URL is "captured" and sent to the view function as a keyword argument. The: question_id> part of the string defines the name used to identify the matching pattern, and the <int: part is the converter that determines the pattern that matches this part of the URL path.

In this case, the access / polls / 34 / will leave the string 34 /, so it will match with the second path (). After that, the request is passed to the specified view function. In this case, the request is passed to the detail () method of polls / views.py. Looking at it, request and question_id are specified as arguments, so as a result

detail(request=<HttpRequest object>, question_id=34)

Arguments are passed to detail (), and the method is executed. We will check later what kind of processing is actually done.

About templates


   'DIRS': [os.path.join(BASE_DIR, 'templates')],
   'APP_DIRS': True,

This part of settings.py is the key, first specify where to put the template html in DIRS. If you specify a template for only one application, the application folder name will be entered instead of BASE_DIR, but after setting BASE_DIR and then setting ʻAPP_DIRS to True`, the subdirectory of the folder specified above will be the application. You can set it to search by the name of the application folder and apply the template.

In other words, in this case, the application folder name is polls, so the directory where the templates are saved is templates / polls. The render () method can specify a request as the first argument, a template name as the second argument, and a dictionaryas the third argument. Then, it has the role of creating aHttpResponseobject based on the received arguments and returning it. It seems that this kind of processing is called rendering. Rendering is an image of processing that expresses certain information by changing it into a form. In this case, information such asrequest objects (sessionandget, post) and context` (database data). And the template html file are combined well, It seems that it is processing like molding as a browser screen.

Also, by importing the render class, you don't have to import the loader class or the HttpResponse class. However, the HttpResponse class has other roles, so it seems safe to keep it.

The next exception is.


from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})


This is a familiar form of the so-called try-catch. You can get a 404 error by importing the Http404 class from the django.http module. The code that raises an exception depending on whether or not the question object is assigned to the question variable. To make it a little easier to understand, if the data with the requested ID does not exist, an exception will be issued. As with the render () method, which also played the role of loader and HttpRespose, you can import more concisely written methods from the django.shortcuts module.

from django.shortcuts import get_object_or_404, render

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

By specifying the model name and key in the get_object_or_404 () method, try-catch will be processed automatically. You can set multiple keys, for example, if you specify get_object_or_404 (User, pk = 1, name ='tanaka'), the primary key is 1 and the name key value is tanaka. You will get a 404 error. By the way, there is also a method called get_list_or_404 (). It is a method to get the value from the model in the same way, but this time, based on the specified key, narrow down with the filter () method and get all with list. For example, if you specify get_list_or_404 (User, pk = 1, name ='tanaka') as before, will you get all the data with primary key 1 and name key value tanaka and return it as a list? If none of them exist, you will get a 404 error.

About the template system

It is a template system that was also Laravel, but there is not much difference in writing and usage.

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

For example, with this description, you may have noticed it just by looking at it, but if it is {{}} and double curly braces, it will be a variable expression. In other words, it represents the attributes of the variable, and it says that the question_text part of the Question object will be included here.

As a process

From the document

The template system uses dot search syntax to access the attributes of variables. Taking {{question.question_text}} as an example, Django first does a dictionary search on the question object. If that fails, it will now search as an attribute and in this case it will succeed. If the attribute search fails, the list index will be searched.

It means that. As you can see from the creation of this tutorial, the content of the question is included in the h1 tag. Therefore, there are multiple questions, and it is difficult to create a template each time ... So it is OK if you write this way and understand that the contents of the h1 tag will change depending on the content of the question. ..

Next, in the case of one curly brace called {}. This is making a method call.

The processing this time is as follows.

From the document

The method call is done inside a {% for%} loop. question.choice_set.all is interpreted as question.choice_set.all () in Python code. As a result, it returns an iterable object consisting of Choice objects, which can be used with the {% for%} tag.

In other words, you can list as many li tags as there are choice.choice_text objects obtained by this method. In this case, it is an expression of the answer to the content of the question. There are multiple ways to answer one question, so it's okay if you know that it is expressed in this way.

Also, remember, for example, that you specified name earlier in polls.urls?

path('<int:question_id>/', views.detail, name='detail'),

It's like this. If you specify it like this, you don't need to write the URL path by using the url tag in the template. For example


<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

It is such a description. Normally, you have to specify ʻURL or path in the href attribute of the ʻa tag. However, I have defined in advance that detail is the name of the path / polls /'<int: question_id> /'. So, if you write detail as above and then put ʻint type named question_id(question.id in this case), it will be a path. As an aside, if you want this path to look likepolls / specifics / 12 /, edit polls / urls.py`.

Namespace

Finally, the namespace. By defining a namespace in ʻurls.py of each application folder in advance, it will automatically determine which application's ʻURLconf should be used when managing multiple application folders in one project. I will.

polls/urls.py



#Add the following
app_name = 'polls'

Specify like this. And on the template side, in the part of specifying the name of the URL path

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

I will specify it with a namespace like this. This means that the polls app's detail view path goes here.

reference

What is rendering in the first place? [Easy-to-understand explanation for beginners] What is Django's class-based view as_view?

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 (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 ―― 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 external commands in python
8 Frequently Used Commands in Python Django
Web teaching materials for learning Python
Web application development memo in python
[For beginners] Django -Development environment construction-
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
Implemented Perceptron learning rules in Python
Run unittests in Python (for beginners)
Prepare Python development environment for each project in Windows environment (VSCode + virtualEnvWrapper + Pylint)
Development of MTG card evaluation posting site ~ Django app release in 5 weeks ~