Djangoでジェネリックビューを使ったCRUDです。
1.環境
カテゴリ | バージョンなど |
---|---|
os | windows 10 home 64bit |
python | 3.6.5 |
django | 2.1.4 |
2.アプリケーションの作成
(1)以下のコマンドを実行してアプリケーションを作成する。
(venv) C:\data\python\myproject>python manage.py startapp employee
(2)ファイル構成
完成後は以下のようなフォルダ/ファイル構成になります。
employee
│ admin.py
│ apps.py
│ models.py
│ tests.py
│ urls.py
│ views.py
│ __init__.py
├─migrations
│ │ 0001_initial.py
・・・
├─templates
│ └─employee
│ create.html
│ delete.html
│ detail.html
│ index.html
│ update.html
3.migrate
まずはmodelを永続化するために、modelを作成してmigrateしていきます。
(1)models.pyを編集する。
from django.db import models
from django.urls import reverse
# Create your models here.
class Employee(models.Model):
"""従業員"""
name = models.CharField('氏名', max_length=255)
age = models.IntegerField('年齢', blank=True, default=0)
birthday = models.DateField('誕生日', blank=True)
hiredate = models.DateField('入社日', blank=True)
retiredate = models.DateField('退社日', blank=True)
createddate = models.DateTimeField('登録日時', auto_now_add=True)
lastmodifieddate = models.DateTimeField('最終更新日時', auto_now=True)
def __str__(self):
return self.name
def get_absolute_url(self):
"""
更処理完了時の戻り先URL
"""
return reverse('employee:index')
(2)プロジェクトにアプリケーションを追加する。
- settings.py
INSTALLED_APPSに以下のように追加します。
INSTALLED_APPS = [
'accounts.apps.AccountsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
・・・
'bootstrap4', #追加
'employee', #追加
]
bootstrap4はこの記事を参考にしてください。
- urls.py
myprojectのurls.pyの「urlpatterns 」にも追加しておきます。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
・・・
path('employee/', include('employee.urls')), # ←ここを追加
path('admin/', admin.site.urls),
]
(3)migrate
modelをmigrateします。
(venv) C:\data\python\myproject>manage.py makemigrations employee
・・
(venv) C:\data\python\myproject>manage.py migrate employee
4.crudの実装
準備ができましたのでいよいよ実装していきます。
(1)urls.py
最初にルーティング(urls.py)です。CRUDは「create, read, update, delete」という意味で、それぞれのURLを設定しておきます。ただ、readは、一覧表示と詳細表示の2つがあるので、readとせず、それぞれindex, detailとしています。
from django.urls import path
from . import views
app_name = 'employee'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('employee/create/', views.CreateView.as_view(), name='create'),
path('employee/<int:pk>/', views.DetailView.as_view(), name='detail'),
path('employee/<int:pk>/update/', views.UpdateView.as_view(), name='update'),
path('employee/<int:pk>/delete/', views.DeleteView.as_view(), name='delete'),
]
(2)views.py
viewには、ジェネリックビュー()を使います。
from django.urls import reverse_lazy
from django.views import generic
from .models import Employee
from pure_pagination.mixins import PaginationMixin
class IndexView(PaginationMixin, generic.ListView):
model = Employee
paginate_by = 5
ordering = ['-createddate']
template_name = 'employee/index.html'
class DetailView(generic.DetailView):
model = Employee
fields = '__all__' # or ['colmunname', 'colmunname', 'colmunname']
template_name = 'employee/detail.html'
class CreateView(generic.edit.CreateView):
model = Employee
fields = '__all__' # or ['colmunname', 'colmunname', 'colmunname']
template_name = 'employee/create.html'
class UpdateView(generic.edit.UpdateView):
model = Employee
fields = '__all__' # or ['colmunname', 'colmunname', 'colmunname']
template_name = 'employee/update.html'
class DeleteView(generic.edit.DeleteView):
model = Employee
success_url = reverse_lazy('employee:index')
template_name = 'employee/delete.html'
(3)html
最後はhtmlです。
{% extends 'commons/base.html' %}
{% load static %}
{% block links %}
<style media="screen">
</style>
{% endblock %}
{% block headertitle %}
新規作成
{% endblock %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>{{form.as_table}}</table>
<button type="submit" class="submit btn btn-info">登録</button>
</form>
{% endblock %}
{% extends 'commons/base.html' %}
{% load static %}
{% block links %}
<style media="screen">
</style>
{% endblock %}
{% block headertitle %}
変更
{% endblock %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>{{form.as_table}}</table>
<button type="submit" class="submit btn btn-info">登録</button>
</form>
{% endblock %}
{% extends 'commons/base.html' %}
{% load static %}
{% block links %}
<style media="screen">
</style>
{% endblock %}
{% block headertitle %}
削除
{% endblock %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
<tr><td>氏名 :</td><td>{{ object.name }}</td></tr>
<tr><td>年齢 :</td><td>{{ object.age }}</td></tr>
<tr><td>生年月日 :</td><td>{{ object.birthday }}</td></tr>
<tr><td>入社日 :</td><td>{{ object.hiredate }}</td></tr>
<tr><td>退社日 :</td><td>{{ object.retiredate }}</td></tr>
<tr><td>登録日時 :</td><td>{{ object.createddate }}</td></tr>
<tr><td>更新日時 :</td><td>{{ object.lastmodifieddate }}</td></tr>
<br/>
</table>
<br/>
<br/>
<button type="submit" class="submit delete btn btn-danger">削除</button>
</form>
{% endblock %}
{% extends 'commons/subwinbase.html' %}
{% load static %}
{% block links %}
<style media="screen">
td{
padding:5px;
}
</style>
{% endblock %}
{% block headertitle %}
詳細表示
{% endblock %}
{% block content %}
<div>
<table>
<tr><td>氏名 </td><td>{{ object.name }}</td></tr>
<tr><td>年齢 </td><td>{{ object.age }}</td></tr>
<tr><td>生年月日 </td><td>{{ object.birthday }}</td></tr>
<tr><td>入社日 </td><td>{{ object.hiredate }}</td></tr>
<tr><td>退社日 </td><td>{{ object.retiredate }}</td></tr>
<tr><td>登録日時 </td><td>{{ object.createddate }}</td></tr>
<tr><td>更新日時 </td><td>{{ object.lastmodifieddate }}</td></tr>
</table>
<br/>
</div>
{% endblock %}
{% extends 'commons/subwinbase.html' %}
{% load static %}
{% block links %}
<link href="{% static 'css/pagination.css' %}" rel="stylesheet">
<style media="screen">
.pagination > div {
display: inline-block;
}
</style>
{% endblock %}
{% block headertitle %}
一覧
{% endblock %}
{% block content %}
<table class="table table-striped table-bordered table-sm">
<thead>
<tr>
<th>ID</th>
<th>氏名</th>
<th>年齢</th>
<th>生年月日</th>
<th>入社年月日</th>
<th>退職年月日</th>
<th><a href="{% url 'employee:create' %}" class="btn btn-primary btn-sm">追加</a></th>
</tr>
</thead>
<tbody>
{% for employee in object_list %}
<tr>
<td>{{ employee.id }}</td>
<td>{{ employee.name }}</td>
<td>{{ employee.age }}</td>
<td>{{ employee.birthday }}</td>
<td>{{ employee.hiredate }}</td>
<td>{{ employee.retiredate }}</td>
<td>
<a href="{% url 'employee:update' employee.pk %}" class="btn btn-info btn-sm">修正</a>
<a href="{% url 'employee:delete' employee.pk %}" class="btn btn-danger btn-sm">削除</a>
<a href="{% url 'employee:detail' employee.pk %}" onclick="OpenSubWin(this);return false;" class="btn btn-success btn-sm">照会</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<br/>
<!-- pagination -->
{% include 'commons\pagination2.html' %}
{% endblock %}
base.html、pagination2.htmlはそれぞれ以下の記事を参照。
Python+Django+psycopg2で内部結合クエリを試す
DjangoでPaginationを実装する
以上で実装が完了
※本番ではformを作成して入力項目のバリデーションなども実装が必要でしょうが、この記事ではここまでとします。
5.完成イメージ
あとはデータを入力して動かしてみましょう。
わずかなコードでCRUDが実装できます。
以上です。
追記 2018.12.14
detail.htmlで使用しているjavascript「OpenSubWin」はこちらを参照ください。