Djangoで家計簿のWebアプリケーションを作る 4 日ごとの支出額を可視化する
Djangoで家計簿のアプリケーション作ってみた、という記事の4つ目です。今回は日ごとの支出をmatplotlibでグラフ化します。Webアプリでグラフを作る場合にはJavascriptに便利なツールがそろっているのですが、Javascriptは現在勉強中なので今回はmatplotlibでグラフを作ってみます。
過去記事は下のリンクをどうぞ
構成
views.py
中にグラフを書いて保存するコードを書きます。画像の保存形式は画質がいいのでSVGを使います。この関数をビューを表示するときに動くindex
が呼ばれるたびに実行するようにします。
グラフを書く
money/views.py
import calendar import datetime from django.shortcuts import render, redirect from django.utils import timezone import matplotlib.pyplot as plt import pytz from .models import Money from .forms import SpendingForm plt.rcParams['font.family'] = 'IPAPGothic' #日本語の文字化け防止 # Create your views here. TODAY = str(timezone.now()).split('-') def index(request, year=TODAY[0], month=TODAY[1]): money = Money.objects.filter(use_date__year=year, use_date__month=month).order_by('use_date') total = 0 for m in money: date = str(m.use_date).split(' ')[0] m.use_date = '/'.join(date.split('-')[1:3]) total += m.cost form = SpendingForm() context = {'year' : year, 'month' : month, 'money' : money, 'total' : total, 'form' : form } draw_graph(year, month) #追加 if request.method == 'POST': data = request.POST use_date = data['use_date'] cost = data['cost'] detail = data['detail'] category = data['category'] use_date = timezone.datetime.strptime(use_date, "%Y/%m/%d") tokyo_timezone = pytz.timezone('Asia/Tokyo') use_date = tokyo_timezone.localize(use_date) use_date += datetime.timedelta(hours=9) Money.objects.create( use_date = use_date, detail = detail, cost = int(cost), category = category, ) return redirect(to='/money/{}/{}'.format(year, month)) return render(request, 'money/index.html', context) def draw_graph(year, month): #追加 money = Money.objects.filter(use_date__year=year, use_date__month=month).order_by('use_date') last_day = calendar.monthrange(int(year), int(month))[1] + 1 day = [i for i in range(1, last_day)] cost = [0 for i in range(len(day))] for m in money: cost[int(str(m.use_date).split('-')[2])-1] += int(m.cost) plt.figure() plt.bar(day, cost, color='#00bfff', edgecolor='#0000ff') plt.grid(True) plt.xlim([0, 31]) plt.xlabel('日付', fontsize=16) plt.ylabel('支出額(円)', fontsize=16) #staticフォルダの中にimagesというフォルダを用意しておきその中に入るようにしておく plt.savefig('money/static/images/bar_{}_{}.svg'.format(year, month), transparent=True) return None
今回追加したのは2か所だけです。
テンプレートを更新する
ビューに合わせてテンプレートを書き直します。
money/templates/money/index.html
<!DOCTYPE html> {% load static %} <html> <head> <meta charset="utf-8"> <title>HousekeepingBook</title> <link rel="stylesheet" type="text/css" href="{% static 'money/style.css' %}"> </head> <body> <h1>{{ year }}年{{ month }}月</h1> <form action="/money/" method="post"> {% csrf_token %} {{ form.as_table }} <input type="submit" value="送信"> </form> <div class="wapper"> <div class="main"> <table> <tr> <th>日付</th> <th>用途</th> <th>カテゴリー</th> <th>金額</th> </tr> {% for m in money %} <tr> <td>{{ m.use_date }}</td> <td>{{ m.detail }}</td> <td>{{ m.category }}</td> <td>{{ m.cost }}円</td> </tr> {% endfor %} </table> <div class="tot"> 合計:{{ total }}円 </div> </div> <div class="main"> <img src="/static/images/bar_{{ year }}_{{ month }}.svg" width=80% </div> </div> </body> </html>
imgタグの画像ファイルへのパスは、{% static %}
を使うのが良いのでしょうが、今回はファイル名に{{ year }}
や{{ month }}
といった変数が入ってくるので、ふつうに書きました。