この記事は、「Djangoを使用した顧客管理システムの作成」の5つ目の記事です。
いよいよ完成も近くなってきました。今回は、検索機能とダッシュボード機能を作っていきます。
検索機能の作成
今回は、商談履歴(上記の記事で作成)を年月、顧客名、カテゴリで検索できる機能を追加していきたいと思います。
filters.pyの作成
検索機能を追加するのdjango-filter
を使用していきます。
pip install django-filter
インストールしてない人は、上記でインストールしよう。
django-filter
を使うと検索条件を短いコードで作成することができ、簡単に検索フォームを作ることができます。今回作成したfilters.py
はmodels.py
とかと同じフォルダcrm_app
に保存します。
さっそく作ったfilters.py
を見ていきましょう。
import django_filters
from .models import Deal
class DealFilter(django_filters.FilterSet):
year = django_filters.NumberFilter(field_name='date',lookup_expr='year',label='年')
month = django_filters.NumberFilter(field_name='date',lookup_expr='month',label='月')
customer_name = django_filters.CharFilter(field_name='customer',lookup_expr='icontains',label='顧客名')
category = django_filters.ModelChoiceFilter(
queryset = Category.objects.all(),
label = 'カテゴリ',
)
class Meta:
model = Deal
fields = ['year','month','customer_name','category']
まずは、djnago-filter
のNumberFilter
を使用して、数値に対しての検索フィルターを作成しています。Deal
クラスのdate
フィールドを対象として、年月をフィルタリングしています。引数のlookup_expr
について、後ほど詳しく説明します。
次にCharFilter
を使って、文字列に対しての検索フィルターを作成しています。customer
フィールドを対象とすることで、顧客名でフィルタリングしています。
最後にModelChoiceFilter
を使って、カテゴリで検索ができるようにしています。queryset
でCategory
モデルのすべてのオブジェクトを取得し、プルダウン形式(選択式)で選択できるフィルターを作成しています。
filters.pyの適用
では、作成したfilters.py
をview.py
に適用していきます。
from .filters import DealFilter
...
#商談履歴の閲覧
class DealList(View):
def get(self,request):
sort_by = request.GET.get('sort', 'date') # デフォルトは商談日でソート
deals = Deal.objects.all().order_by(sort_by)
deal_filter = DealFilter(request.GET,queryset=deals)#フィルタ適用
filtered_deals = deal_filter.qs
paginator = Paginator(filtered_deals,10) #1ページに10件
page = request.GET.get('page')
paginated_deals = paginator.get_page(page)
context = {
'deal_filter':deal_filter,
'deals':paginated_deals,#フィルタ後のデータのみを渡す
}
return render(request,'crm_app/deal_list.html',context)
まずは、sort_by
変数を作成して、ソート(並び替え)をしていきます。sort_by
はURLパラメータにsort
が設定されていたら、それを採用し、なければdate
でソートするというものです。
次にDealFilter
を使用して、検索フォームに入力された内容に対して、Deal
モデル内でフィルタリングを行います。
deal_filter = DealFilter(request.GET,queryset=deals)
は、GETリクエストの内容を基にフィルタリングしています。取得したdeals
オブジェクト内に対しての検索フォームを表しています。フィルタリングを行ったら、.qs
を使用して、フィルタリング後のデータだけ取得します。
ページネーションに渡す値をフィルタリング後のものに変え、検索フォームであるdeal_filter
とフィルタリング後の値をテンプレートに渡しています。
テンプレート以前作成したもの検索フォーム部分を追加します。
...
<form method="GET">
{{ deal_filter.form.as_p }}
<button type="submit">検索</button>
</form>
...
これで、検索機能の完成です。
補足:lookup_exprについて
lookup_expr
とはdjango-filter
で検索するとき、どんな条件で検索するかを決めるオプションです。以下が主に使われるものです。
lookup_expr |
意味 |
---|---|
exact |
完全一致 |
iexact |
大文字小文字を無視した一致 |
contains |
部分一致 |
icontains |
大文字小文字を無視した部分一致 |
year |
年での絞り込み |
month |
月での絞り込み |
day |
日での絞り込み |
gt |
より大きい |
gte |
以上 |
lt |
より小さい |
lte |
以下 |
ダッシュボードの作成
作業内容
-
基本的なダッシュボード作成
- 顧客数、商談数、売上予測(ダミーデータ可)を表示
-
データ集計
- KPIを計算してテンプレートに表示
-
グラフ表示
-
chart.js
などを使用して簡単なグラフを表示
-
ダッシュボードのビュー作成
まずは、ビューを作成していきます。ダッシュボートで必要なのは、顧客数、商談数、売上予測(今回はダミーデータを使用)です。それらを用意していきます。
class Dashboard(View):
def get(self,request):
#基本データの取得
customer_count = Customer.objects.count() #顧客数
deal_count = Deal.objects.count() #商談数
#売上予測(ダミーデータ)
sales_forecast = sum(random.randint(10000,50000) for _ in range(deal_count)) #仮の売上予測
#月ごとの商談件数(グラフ用データ)
monthly_deals = (
Deal.objects
.extra(select={'month':"strftime('%Y-%m',date)"}) #SQLite用(PostgreSQLなら'date_trunc'
.values('month')
.annotate(count=Count('id'))
.order_by('month')
)
months = [entry['month'] for entry in monthly_deals] # x軸(月)
deal_counts = [entry['count'] for entry in monthly_deals] # y軸(商談数)
context = {
'customer_count':customer_count,
'deal_count':deal_count,
'sales_forecast':sales_forecast,
'months':months,
'deal_counts':deal_counts,
}
return render(request,'crm_app/dashboard.html',context)
まずは、Customer
クラスとDeal
クラスから顧客数と商談数を取得します。数を数えるのは、count()
を使用しています。次に売上予測のダミーデータを作成しているのですが、こちらは1商談で10000~50000
円として、ランダムな数値を割り振っています。
次にmonthly_deals
についてです。こちらは月ごとの商談件数のデータをグラフ用に作成している部分です。
上からそれぞれ、
-
Deal
モデルを指定 -
date
フォールドの日付をYYYY-MM
の形に変形し、month
という名前の列を作成 -
month
ごとにデータをグループ化 - 各月ごとの商談数を```id``をカウントすることで取得
- 月ごとに並び替え
を行っています。
次に、months
とdeal_counts
はx軸とy軸のデータを作成しています。monthly_deals
からx軸には月ごとのデータを、y軸には商談数のデータを格納している。
最後に、作成したデータをテンプレートに渡しています。
テンプレートの作成
今回は、base.html
を使用せずに作成しました。base.html
が使えないというわけではなく、新しくjavascript
ファイルを使用する関係で、見直すときにわかりやすいかなという理由です。関係ないよって人はぜひbase.html
を編集してみてください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ダッシュボード</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
{% load humanize %}
<div class="container mt-5">
<h2>ダッシュボード</h2>
<!-- ✅ KPI セクション -->
<div class="row text-center">
<div class="col-md-4">
<div class="card text-white bg-primary mb-3">
<div class="card-header">顧客数</div>
<div class="card-body">
<h3>{{ customer_count }}</h3>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-white bg-success mb-3">
<div class="card-header">商談数</div>
<div class="card-body">
<h3>{{ deal_count }}</h3>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-white bg-warning mb-3">
<div class="card-header">売上予測</div>
<div class="card-body">
<h3>¥{{ sales_forecast|intcomma }}</h3>
</div>
</div>
</div>
</div>
<!-- ✅ 商談数の推移グラフ -->
<div class="card mt-4">
<div class="card-header">月ごとの商談件数</div>
<div class="card-body">
<canvas id="dealChart"></canvas>
</div>
</div>
</div>
<script>
var ctx = document.getElementById('dealChart').getContext('2d');
var dealChart = new Chart(ctx, {
type: 'bar',
data: {
labels: {{ months|safe }}, // x軸
datasets: [{
label: '商談件数',
data: {{ deal_counts|safe }}, // y軸
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
scales: {
y: { beginAtZero: true }
}
}
});
</script>
</body>
</html>
まずグラフ表示のためにchart.js
を使用します。ヘッダーのところにscript
で設定します。
まずはKPIセクションについてです。KPIとは「ビジネスの成果を測るための重要な指標」のことで、要するに成果として、この項目を見ようねっていうことです。今回は、「顧客数」「商談数」「売上予測」の3つの指標を表示しています。
次にグラフを表示している部分についてです。グラフは<canvas id="dealChart"></canvas>
の部分に表示されます。設定しているのが、下の<script></script>
部分です。
script
部分は、
var ctx = document.getElementById(’dealChart’).getContext(’2d’):id=”dealChart”の要素を取得し、2Dグラフィックスを描写するためのコンテキストを取得。html内にの記述が必要。
var dealChart = new Chart(): Chartコンストラクタを使用してグラフを生成。引数のtypeはグラフの種類を設定。今回使用したbarは棒グラフ。他にもline:折れ線グラフやpie:円グラフなどがある。
引数のdata{}:グラフ表示するデータの設定を行う。引数のlabels:{{ months|safe }}は棒グラフのx軸ラベル。months変数が表示される。
引数のdatasets:実際のグラフデータを定義する配列。複数のデータセットを追加することで、複数の系列で表示できる。borderWidthは棒グラフの太さを指定する。
options:{}:グラフ表示のオプションを設定。scalesは軸の設定。今回はy軸を設定している。beginAtZero:trueは目盛りが0から始めるように設定している。
一件しか追加してないですが、しっかりと表示できていますね。
urls.py
の部分は割愛してますが、今までと同じように設定するだけです。
これで、顧客管理システム完成です。まだフォームとかの見た目気を使ってない部分多いですので、改良してみると楽しいかもしれません。
1つ目:Djangoを使用した顧客管理システムの作成
https://qiita.com/tomo0227/items/cc893ea4e8e6cfb6ad77
2つ目:顧客管理システムのモデル作成
https://qiita.com/tomo0227/items/11f6a262ee1da183fd70
3つ目:顧客管理システムのCRUD機能の実装
https://qiita.com/tomo0227/items/054c974e104f81ea82db
4つ目:商談履歴管理システムの作成
https://qiita.com/tomo0227/items/7b9934ab4bc36cdcd4e8
5つ目:Djangoで検索・ダッシュボード機能を作ってみた。
https://qiita.com/tomo0227/items/a86f7bf038e87be11892