こんにちは!Masaです。
11回目の今回は、口座残高推移グラフの改善です。
- Django初心者で簡単なWebアプリケーション作成を考えている人
- Djangoの学び直しをしている人
- Djangoの基礎を身に付けたい人
前回のおさらいと今回やること
9回目と10回目の記事では、口座の詳細ページを作成しました。
その際、残高推移グラフの横軸(日付)が一定間隔にならないことに気づきました。
今回はこの問題を解消していきます!
日付軸の目盛間隔を一定にするために
日付軸の目盛間隔を一定にするために、一定時間おきに残高のデータを記録することにしました。
例えば毎日決まった時間に口座残高を記録しておき、この情報をグラフにプロットしたら目盛の間隔が一定になります。
この方法を実現するために、一定時間おきに処理を行うバックグラウンド処理を導入していきたいと思います。
今回はPythonのAPSchedulerというライブラリを用いてバックグラウンド処理を行います。
APSchedulerの詳細は以下の記事をご覧ください。
新しいモデルを作成
まずは定期実行された口座残高のデータを格納するモデルを作成します。
以下のモデルをmodels.pyに追記してください。
#一定間隔の各口座残高
class AccountHis(models.Model):
date = models.DateField(default=timezone.now)
name = models.ForeignKey(Account, on_delete=models.CASCADE)
balance = models.IntegerField()
def __str__(self):
return str(self.date) +'_' + self.name.name
これはAccountBalanceクラスと変わりありません。
定期処理のプルグラムを作成
次に定期的な処理を行うプログラムを記述します。
バックグラウンド定期処理を行ってくれるAPSchedulerを導入するために事前設定を行います。
詳細は上記の記事に記載してあります。
まず、APSchedulerをインストールしましょう。
コマンドラインで以下の処理を実行しましょう。
pip install apscheduler
次にアプリケーションフォルダ(money_diary)にあるapps.pyに以下のコードを追加します。
from django.apps import AppConfig
class MoneyDiaryConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'money_diary'
#以下追加
def ready(self):
"""起動時に呼び出される"""
from .update import start
start()
これによりrunserver起動時にupdate.pyが実行されるようになります。(update.pyはこの後作成)
update.pyを作成
次に定期処理してくれるプログラムを記述していきます。
アプリケーションフォルダにupdate.pyを作成し、以下のコードを記述してください。
from apscheduler.schedulers.background import BackgroundScheduler
from .models import Account, AccountBalance, AccountHis
#定期実行の処理
def update():
account = Account.objects.values_list('name', flat=True)
for name in account:
account = AccountBalance.objects.all().filter(name__name=name).latest('date')
AccountHis.objects.create(
name = account.name,
balance = account.balance
)
print('更新')
#定期実行のインターバル設定
def start():
scheduler = BackgroundScheduler()
scheduler.add_job(update, 'cron', hour=0)
scheduler.start()
21行目でupdate()を毎時0時に実行する設定になります。
これにより、毎日1回0時に各口座の残高がAccountHisに格納されることになります。
views.pyを更新
最後にテンプレートに渡すデータが変わってくるので、views.pyのAccount_DetailViewを更新します。
class Account_DetailView(View):
def get(self, request, num, year=int(today[0]), month=int(today[1])):
# 選択口座のデータの取得
account = AccountBalance.objects.get(id=num)
# 選択講座の収支データの取得
income = Income.objects.all().filter(account__name=account.name, date__year=year, date__month=month).order_by()
expense = Expense.objects.all().filter(account__name=account.name, date__year=year, date__month=month).order_by()
#グラフのデータ取得
account_his = AccountHis.objects.all().filter(name=account.name)
balance = []
date = []
#グラフ用データをリストに格納
for n in account_his:
date.append(n.date.strftime('%y/%m/%d'))
balance.append(n.balance)
# 月次切り替えの際の条件
if month == 12:
last_year = year
last_month = 11
next_year = year + 1
next_month = 1
elif month == 1:
last_year = year - 1
last_month = 12
next_year = year
next_month = 2
else:
last_year = year
last_month = month - 1
next_year = year
next_month = month + 1
params = {
'account': account,
'income': income,
'expense': expense,
'date': date,
'balance': balance,
'year': year,
'month': month,
'last_year': last_year,
'last_month': last_month,
'next_year': next_year,
'next_month': next_month,
}
return render(request, 'money_diary/account_detail.html', params)
主に9行目から18行目が変更点です。
選択された残高履歴をリストに格納しています。
これで定期処理は完了です。
実際にできているか確認したい人は、update.pyのstart()関数を以下のように変えてテストしてみてください。
def start():
scheduler = BackgroundScheduler()
scheduler.add_job(update, 'interval', seconds=30)
scheduler.start()
これで30秒ごとに定期実行されるようになります。
AccountHisに各口座のデータが格納されていけば正常に動作していると思います。
ラベルの表示を微調整
最後にx軸のラベルの調整をしましょう。
現在のままだと、軸のラベルがプロットされた点すべて表示されてしまいます。
1年分のデータがプロットされていた場合は365個のラベルが表示されることになります。
そのため少し調整して、10個のラベルが表示されるようにしたいと思います。
account_detail.htmlのグラフ詳細部分を少し変更します。
options: {
//凡例非表示
legend: {
display: false
},
scales: {
//X軸(以下追加)
xAxes: [{
ticks: {
autoSkip: true,
maxTicksLimit: 10,
}
}],
yAxes: [{
ticks: {
beginAtZero:true
},
}]
}
}
});
まとめ
今回は残高推移グラフの横軸(日付)の目盛間隔が一定にならない問題に対処しました。
対処方法としては、
- 定期処理を行って、毎日決まった時間に残高データを別で取得する
という方法を取りました。
定期処理は”APScheduler”というPythonのライブラリを使用しています。
次回以降はデザインを少し勉強して、見やすいUIにしていきたいと思います。
次回の記事↓
作成中
コメント