この記事は、「Djangoを使用した顧客管理システムの作成」の4つ目の記事です。
前回顧客管理のCRUD機能を作りました。今回は、商談履歴のCRUD機能を作成していきます。
商談履歴のCRUD機能の実装
作業内容
- 商談履歴のCRUD
- 商談履歴の登録・閲覧・編集・削除するビューとテンプレートの作成
- 顧客ごとの商談履歴を一覧表示
ビューの作成
↑前回の記事で作成したviews.pyを編集していきます。前回の記事ですでに商談履歴モデルDeal
はインポート済みなので、クラスの作成から行っていきます。
from django.core.paginator import Paginator #追加
from .forms import AddDealForm #追加
#商談履歴の閲覧
class DealList(View):
def get(self,request):
sort_by = request.GET.get('sort', 'date') # デフォルトは商談日でソート
deal = Deal.objects.all().order_by(sort_by)
paginator = Paginator(deal,10) #1ページに10件
page = request.GET.get('page')
deals = paginator.get_page(page)
return render(request,'crm_app/deal_list.html',{'deal':deals})
#商談情報の追加
class AddDeal(View):
def get(self,request):
form = AddDealForm()
return render(request,'crm_app/add_deal.html',{'form':form})
def post(self,request):
form = AddDealForm(request.POST)
if form.is_valid():
form.save()
return redirect('deal_list')
return render(request,'crm_app/add_deal.html',{'form':form})
#商談情報の編集
class EditDeal(View):
def get(self,request,id):
deal = get_object_or_404(Deal,id=id)
form = AddDealForm(instance=deal)
return render(request,'crm_app/edit_deal.html',{'form':form,'id':id})
def post(self,request,id):
deal = get_object_or_404(Deal,id=id)
form = AddDealForm(request.POST,instance=deal)
if form.is_valid():
form.save()
return redirect('deal_list')
return render(request,'crm_app/edit_deal.html',{'form':form,'id':id})
#商談情報の削除
class DeleteDeal(View):
def get(self,request,id):
deal = get_object_or_404(Deal,id=id)
return render(request,'crm_app/delete_deal.html',{'deal':deal})
def post(self,request,id):
deal = get_object_or_404(Deal,id=id)
deal.delete()
return redirect('deal_list')
deal_list = DealList.as_view()
add_deal = AddDeal.as_view()
edit_deal = EditDeal.as_view()
delete_deal = DeleteDeal.as_view()
基本的に前回記事で作成したCRUD機能を同様に作っています。違う点として、商談履歴一覧表示にページネーションを付けてみました。ページネーションとは情報をページごとに分割して整理するものです。今回は、商談履歴が1ページに10件だけ表示されるようにし、10件を超える商談履歴が保存されたときは、複数ページ作られるようになっています。
テンプレートの作成
こちらも前回同様に作成したビューを基にdeal_list.html
、add_deal.html
、edit_deal.html
、delete_deal.html
を作成していきます。ベースとして前回作成したbase.html
を使用します。テンプレートは前回とほぼ同じなので、ページネーションを追加したdeal_list.html
のみ紹介します。
{% extends 'base.html' %}
{% block content %}
<div class="container mt-4">
<h2>商談履歴一覧</h2>
<a href="{% url 'add_deal' %}" class="btn btn-primary mb-3">新規商談登録</a>
<div class="mb-3">
<span class="me-2">ソート:</span>
<a href="?sort=date" class="btn btn-outline-secondary btn-sm">商談日</a>
<a href="?sort=customer" class="btn btn-outline-secondary btn-sm">顧客名</a>
<a href="?sort=title" class="btn btn-outline-secondary btn-sm">商談タイトル</a>
<a href="?sort=status" class="btn btn-outline-secondary btn-sm">ステータス</a>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>顧客名</th>
<th>商談日</th>
<th>商談内容</th>
</tr>
</thead>
<tbody>
{% for d in deal %}
<tr>
<td>{{ d.id }}</td>
<td>{{ d.customer }}</td>
<td>{{ d.date|date:"Y/m/d" }}</td>
<td>{{ d.content }}</td>
<td>
<a href="{% url 'edit_deal' d.id %}" class="btn btn-sm btn-warning">編集</a>
<a href="{% url 'delete_deal' d.id %}" class="btn btn-sm btn-danger">削除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
#ページネーション
{% if deal.has_other_pages %}
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
{% if deal.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ deal.previous_page_number }}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}">前へ</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">前へ</span>
</li>
{% endif %}
{% for i in deal.paginator.page_range %}
{% if deal.number == i %}
<li class="page-item active">
<span class="page-link">{{ i }}</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ i }}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if deal.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ deal.next_page_number }}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}">次へ</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">次へ</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
{% endblock %}
上記のプログラムの一覧表示の部分は前回とほぼ同じなので、ページネーション部分から説明していきます。
{% if deal.has_other_pages %}
は、複数ページあるときTrue
を返します。つまり商談履歴が11件以上あるとき、このコードより下の部分が表示されるということです。
{% if deal.has_previous %}
は、「前のページがあるか」を確認しています。前のページがあるときTrue
を返し、リンクを表示します。
{% for i in deal.paginator.page_range %}
は、ページ数に応じて、ページ番号を作成しています。今いるページ以外のページ番号は、リンクにして、ページ移動ができるようにしています。
{% if deal.has_next %}
は、「次のページがあるか」を確認しています。動作としては{% if deal.has_previous %}
と同様です。
最後にリンクのURL部分<a class="page-link" href="?page={{ i }}{% if request.GET.sort %}&sort={{ request.GET.sort }}{% endif %}">{{ i }}</a>
についてです。?page={{ i }}
はURLにページ番号を渡している部分です。
https://example.com/?page=2
のようなURLを見たことがあると思います。これと同じようにURLを渡しているということです。
{% if request.GET.sort %}
の部分は現在のページはソート(並び方の指定)がされているかを確認しています。ページが移動してソートが変わるのは使い勝手が悪くなってしますので、ソート内容も引き継ぐために使用しています。
フォームの作成とルーティング設定
ここも前回とほぼ同じなので、さらっと行きます。
crm_app/forms.py
にAddDealForm
クラスを作成します。
class AddDealForm(forms.ModelForm):
class Meta:
model = Deal
fields = ['customer','title','date','status','content','responsible_staff']
違いとしては、field
ぐらいですね。モデルが違うので、field
が違うのは当たり前です。
ルーティング設定は、プロジェクトのほうは前回設定したので、アプリケーションのほうだけ設定します。
urlpatterns = [
...
#追加
path('deals/',deal_list,name='deal_list'),
path('deals/add/',add_deal,name='add_deal'),
path('deals/<id>/edit/',edit_deal,name='edit_deal'),
path('deals/<id>/delete/',delete_deal,name='delete_deal'),
]
ここはURLの名前が違うだけです。
今回はここまでにします。今までの部分だけでも普通にwebアプリとして成り立つと思います。
次回は検索機能とダッシュボード機能を追加していきます。