pyhaya’s diary

機械学習系の記事をメインで書きます

Djangoで家計簿のWebアプリケーションを作る 4 日ごとの支出額を可視化する

Djangoで家計簿のアプリケーション作ってみた、という記事の4つ目です。今回は日ごとの支出をmatplotlibでグラフ化します。Webアプリでグラフを作る場合にはJavascriptに便利なツールがそろっているのですが、Javascriptは現在勉強中なので今回はmatplotlibでグラフを作ってみます。

過去記事は下のリンクをどうぞ

pyhaya.hatenablog.com

pyhaya.hatenablog.com

pyhaya.hatenablog.com

開発環境

構成

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 }}といった変数が入ってくるので、ふつうに書きました。

ここまでのページの感じ

f:id:pyhaya:20181110094204p:plain

次回記事
pyhaya.hatenablog.com