OS: Ubuntu 18.04 Python: 3.6.8 Django: 2.2.5 -> 2.2.8
We will add more about Windows later. I don't have a Mac, but it's probably the same as Linux (?). Add if possible.
Refer to the article Last time, and it is assumed that the directory structure is as follows. If you have not set it yet, please create the environment first.
We will create an app from here.
Type django-admin startapp mytodo
on the console.
You can also use python manage.py startapp mytodo
.
After creation, the directory + file of the application called mytodo
will be created as shown below.
.
|-- config
| |-- __init__.py
| |-- __pycache__
| |-- settings.py
| |-- urls.py
| `-- wsgi.py
|-- db.sqlite3
|-- manage.py
|-- myenv
| |-- bin
| |-- include
| `-- lib
`-- mytodo
|-- __init__.py
|-- admin.py
|-- apps.py
|-- migrations
|-- models.py
|-- tests.py
`-- views.py
Set Django's timezone and language first.
settings.py
#Default'EN-en'
LANGUAGE_CODE = 'ja'
#Default'UTC'
TIME_ZONE = 'Asia/Tokyo'
Currently, the created Todo app is unknown to Django. In order for Django to recognize your application, you need to add your application to the settings in config / settings.py
.
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'mytodo', #add to
]
This completes the registration of the application, and finally we will create the application.
For Todo, it is more practical to include the creation date and end date, but this time it will be much easier. The model defined this time is as follows.
models.py
from django.db import models
class Task(models.Model):
doing = 0
done = 1
TASK_STATUS_CHOICES = [
(doing,'in progress'),
(done,'Done'),
]
title = models.CharField(max_length=50)
body = models.models.TextField()
status =models.IntegerField(default=0,choices=TASK_STATUS_CHOICES)
After coding the model, run python manage.py make migrations
on the console at some hierarchy in manage.py.
This command creates the files needed to create the DB from the model.
If it is created without error, it will be displayed as below.
(myenv)~/Projects/python/django_handson$ python manage.py makemigrations
Migrations for 'mytodo':
mytodo/migrations/0001_initial.py
- Create model Task
At this point, there are no changes to the DB. By passing the following python manage.py migrate
command, the previous migration file will be executed for the DB.
(myenv)~/Projects/python/django_handson$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, mytodo, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying mytodo.0001_initial... OK
Applying sessions.0001_initial... OK
In addition to TODO, the character user is displayed. As an aside, the User model provided by Djnago by default is reflected in the DB.
If you can do this, the model creation is complete.
We will implement CRUD based on the model created earlier. When developing by myself, I write in the order of view → template → routing, but I think that there are individual differences, so if you get used to it, write in your own order.
First, create a page that displays all Todo in a list. When displaying one model in one column, using Django's class-based view is a lot easier because it reduces the amount of code.
The role of the view is to get the data from the DB from the received request and return it as an embedded response in the template.
There are two ways to write a view: a function-based view and a class-based view. I'll call either, but this time I'll write in class-based view.
Class-based views include ListView, DetailView, for reference. CreateView, UpdateView, DeleteView, etc. are provided for updating. By using these, it is possible to prepare a view in an instant for simple processing.
This time I will create a list, but the necessary description is as follows.
mytodo/views.py
from django.views.generic import ListView
from mytodo.models import Task
class TaskListView(ListView):
model = Task
template = 'mytodo/list.html'
For model
, specify the model you want to display. Import and use the model you just created.
The template is a file with python control statements embedded in HTML and has the extension .html
.
Translated into Japanese, it is called a template or type, but it is a type for embedding the value fetched from the DB etc. by the view. Embedding the value obtained from the template and DB in the view is called rendering. In the view, Django spits out an html file with embedded data based on the controls written in the template file.
{{}}
Is used to display data, and {%%}
is used to embed Python-like controls.
First, describe the location of the template folder in settings.py as follows.
config/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')], #Change
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Create a templates folder in the same hierarchy as manage.py
, and create a folder called mytodo in it.
Create a file called list.html in it. This time, we will not cover the appearance at all, so create an appropriate html file
templates/mytodo/list.html
<h1>list</h1>
<ul>
{% for task in object_list %}
<li><a href="#">{{ task.title }}</a> {{ task.get_status_display }}</li>
{% endfor %}
</ul>
Make settings to call the appropriate view from the request url. Set in the urls.py file.
You can write everything in urls.py in the config
folder, but when you create multiple apps, it will overflow with a lot of code and it will significantly impair maintainability. It also compromises the portability of the app.
Therefore, it is common practice to create urls.py in the mytodo
app and include it on the config
side.
First, create mytodo / urls.py
and edit it.
urls.py
from django.urls import path
from .views import TaskListView
app_name = 'mytodo'
urlpatterns = [
path('',TaskListView.as_view(), name='task-list'),
]
In urls.py, associate the requested URL with the view. Add this on the config side.
config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('mytodo/', include('mytodo.urls',namespace='mytodo')),#add to
]
The path
function can register the character string to be registered after the'/' of url in the first argument, and view and other URLConf in the second argument.
Routing is completed by creating up to this point.
Let's check immediately Start the server with python manage.py runserver
and check it.
You see Page not found because you haven't routed anything to the route. The registered urls are listed a little below.
Add mytodo to the url and access it as http://127.0.0.1:8000/mytodo
.
Currently, no data is registered, so only the headline is displayed. It is pure white.
Follow the same procedure to implement CRUD CREATE.
Create will be implemented using a class-based view as well. I will add it to views.py earlier.
mytodo/views.py
import django.views.generic import ListView,CreateView #Postscript
(Omission)
class TaskCreateView(CreateView):
model = Task
fields = '__all__'
initial = {'status':0}
template_name = 'mytodo/create.html'
success_url = reverse_lazy('mytodo:task-list')
The implementation method is to register model and template in the same way as ListView.
initial can set the initial state of the Choice field of the Task
model.
For fields, you can specify the data to be received on the server side.
This time we are supposed to receive all the data, but it is also possible to receive only the title
in the Task
model.
Next, create a template.
templates/mytodo/create.html
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Registration">
</form>
In {{form.as_p}}
, the html of the form corresponding to the model and fields of CreateView is generated.
Applying css to the generated form requires some ingenuity, but this time let's enjoy the unique look of html with a taste.
Don't worry about {% csrf_token%}
.
Register the view in urls.py.
mytodo/urls.py
from django.urls import path
from .views import TaskListView, TaskCreateView #Postscript
app_name = 'mytodo'
urlpatterns = [
path('',TaskListView.as_view(), name='task-list'),
path('create',TaskCreateView.as_view(), name='task-create'),#Postscript
]
The last name
in the path function can be named url.
It can be used as an argument to functions such as reverse_lazy
that appeared in views.py earlier.
This completes the implementation of Create. Start the server and access this URL http://127.0.0.1:8000/mytodo/create. If you see a tasty form like the one below, you're successful.
Let's register some as a trial.
The rest are UPDATE and DELETE of CRUD, but create DetailView first. Currently only the list of tasks (List View), but we will create a page (Detail View) that displays more detailed information on the tasks.
Create from the view as before. The implementation is very simple as below
mytodo/views.py
from django.views.generic import ListView,CreateView,DetailView
(Omission)
class TaskDetailView(DetailView):
model = Task
template_name = 'mytodo/detail.html'
The template implementation is as follows: In the same way, create a file called detail.html in the templates / mytodo folder.
templates/mytodo/detail.html
<h1>Details</h1>
<div>title:{{object.title}}</div>
<div>status:{{object.get_status_display}}</div>
<div>Contents:{{object.body}}</div>
<p><a href="#">Edit</a></p>
Finally, register the URL.
Path ('detail', TaskDetailView.as_view (), name ='task-detail') in the list of `ʻurl patterns
] `` Add.
This completes the implementation of DetailView.
Implement the transition from the list page to DetailView. Edit the a tag link in list.html.
templates/mytodo/detail.html
<h1>Details</h1>
<div>title:{{object.title}}</div>
<div>status:{{object.get_status_display}}</div>
<div>Contents:{{object.body}}</div>
<p><a href="{% url 'mytodo:task-update' object.pk%}">Edit</a></p> #Change
You can get the primary key of the object passed to the template with object.pk.
This will be implemented from View as well.
mytodo/views.py
from django.views.generic import ListView,CreateView,DetailView, UpdateView
from django.urls import reverse_lazy
from mytodo.models import Task
(Omission)
class TaskUpdateView(UpdateView):
model = Task
fields = '__all__'
template_name = 'mytodo/update.html'
success_url = reverse_lazy('mytodo:task-list')
It's almost the same as CreateView. If you want to limit the fields that allow updates, you can play with fields.
Since it is almost the same work, we will implement the routing and template at once.
The template is exactly the same as Create.
templates/mytodo/update.html
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Registration">
</form>
Add a new UpdateView to the routing. Like detail, the primary key determines which data should be updated. ..
mytodo/urls.py
urlpatterns = [
path('',TaskListView.as_view(), name='task-list'),
path('detail/<int:pk>/',TaskDetailView.as_view(), name='task-detail'),
path('create/', TaskCreateView.as_view(), name='task-create'),
path('update/<int:pk>/', TaskUpdateView.as_view(), name='task-update'), #add to
]
We will make some changes so that the transition to this edit screen can be performed from the details screen.
templates/mytodo/detail.html
<h1>Details</h1>
<div>title:{{object.title}}</div>
<div>status:{{object.get_status_display}}</div>
<div>Contents:{{object.body}}</div>
<p><a href="{% url 'mytodo:task-update' object.pk%}">Edit</a></p>
It's finally the end. Implement a delete view. As in the example, we will implement it from the view.
View implementation.
mytodo/views.py
from django.views.generic import ListView,CreateView,DetailView, UpdateView
from django.urls import reverse_lazy
from mytodo.models import Task
(Omission)
class TaskDeleteView(DeleteView):
model = Task
template_name = 'mytodo/delete.html'
success_url = reverse_lazy('mytodo:task-list')
Template implementation. It's very simple because you can delay deleting it
templates/mytodo/delete.html
<form action="" method="post">
{% csrf_token %}
<p>Do you really want to delete this?</p>
<p><input type="submit" value="Yes"></p>
<p><a href="{% url 'mytodo:task-list' %}">Return</a></p>
</form>
Routing implementation. The final type is as follows.
mytodo/urls.py
from django.urls import path
from .views import TaskListView, TaskCreateView, TaskDetailView, TaskUpdateView, TaskDeleteView
app_name = 'mytodo'
urlpatterns = [
path('',TaskListView.as_view(), name='task-list'),
path('detail/<int:pk>/',TaskDetailView.as_view(), name='task-detail'),
path('create/', TaskCreateView.as_view(), name='task-create'),
path('update/<int:pk>/', TaskUpdateView.as_view(), name='task-update'),
path('delete/<int:pk>/', TaskDeleteView.as_view(), name='task-delete'), #add to
]
Finally, I added the url that transitions to this deleted view. By the way, list.html is processed by using the control statement of the template.
templates/mytodo/list.html
<h1>list</h1>
<a href="create/"><p>New addition</p></a>
<ul>
{% for task in object_list %}
{% if task.status != 0 %}
<li><del><a href="detail/{{ task.id }}">{{ task.title }}</a> </del>{{ task.get_status_display }} <a href="{% url 'mytodo:task-delete' task.pk %}">Delete</a></li>
{% else %}
<li><a href="detail/{{ task.id }}">{{ task.title }}</a> {{ task.get_status_display }} <a href="{% url 'mytodo:task-delete' task.pk %}">Delete</a></li>
{% endif %}
{% empty %}
<li>No tasks</li>
{% endfor %}
</ul>
Thank you for staying with us until the end of the article about using amateur Django. If you have any mistakes, please do not hesitate to wait.
Recommended Posts