・ioByteIO → io.BytesIO
・plt.saveconfig → plt.savefig
・get_context_data()
内で return contextしていないので、設定したデータがテンプレートに渡されていません。
・MoneyListView.home()
でグラフデータのレンダリングをして、テンプレートに渡そうとしているようですが、 MoneyListViewのget_data_context()の中でデータベースから取得し計算したデータを、
どうやってグラフデータ作成に利用するか、というところについては、
グラフ画像のバイナリをBase64エンコードしてテンプレートに渡すというアプローチをとろうとされているようなので、グラフデータ作成処理部分は汎用ビューから切り離し、エンコード結果を、(データベースから取得し計算したデータと一緒に)contextとして渡した方がすっきりするのではないかと思いました。
以上をまとめたコードが以下です。データの設定等は愚直なままですが元のコード自体がそうなのであしからず。
views.py
python
1# views.py
2
3import io
4import matplotlib
5import matplotlib.pyplot as plt
6import base64
7from django.views.generic import ListView
8from django.db.models import Sum
9from .models import Money
10matplotlib.use('Agg')
11
12
13class MoneyListView(ListView):
14 model = Money
15 context_object_name = 'money_list'
16 template_name = 'moneyapp/money_list.html'
17
18 # db aggregate
19 def get_context_data(self, **kwargs):
20 context = super().get_context_data(**kwargs)
21 avg_amount = Money.objects.aggregate(Sum('amount'))['amount__sum'] / 3
22 context["avg_amount"] = avg_amount
23
24 # payment/per name=Taro
25 pay_taro = Money.objects.filter(name='Taro').aggregate(Sum('amount'))['amount__sum']
26 pay_jiro = Money.objects.filter(name='Jiro').aggregate(Sum('amount'))['amount__sum']
27 pay_koki = Money.objects.filter(name='Koki').aggregate(Sum('amount'))['amount__sum']
28 pay_kaze = Money.objects.filter(name='Kaze').aggregate(Sum('amount'))['amount__sum']
29 context["pay_taro"] = pay_taro
30 context["pay_jiro"] = pay_jiro
31 context["pay_koki"] = pay_koki
32 context["pay_kaze"] = pay_kaze
33
34 # deficiency/per name=Taro
35 deficiency_taro = avg_amount - pay_taro
36 deficiency_jiro = avg_amount - pay_jiro
37 deficiency_koki = avg_amount - pay_koki
38 deficiency_kaze = avg_amount - pay_kaze
39 context["deficiency_taro"] = deficiency_taro
40 context["deficiency_jiro"] = deficiency_jiro
41 context["deficiency_koki"] = deficiency_koki
42 context["deficiency_kaze"] = deficiency_kaze
43
44 x_list = ['Taro', 'Jiro', 'Koki', 'Kaze']
45 y_list = [deficiency_taro, deficiency_jiro, deficiency_koki, deficiency_kaze]
46 create_graph(x_list, y_list)
47 graph = get_image()
48
49 # グラフデータもcontextに。
50 context["graph"] = graph
51
52 # contextを返す。
53 return context
54
55# グラフデータ作成処理部分
56def create_graph(x_list, y_list):
57 plt.cla()
58 plt.bar(x_list, y_list)
59 plt.xlabel('name')
60 plt.ylabel('deficiency')
61
62
63def get_image():
64 buffer = io.BytesIO()
65 plt.savefig(buffer, format='png')
66 image_png = buffer.getvalue()
67 graph = base64.b64encode(image_png)
68 graph = graph.decode('utf-8')
69 buffer.close()
70 return graph
71
urls.py
python
1# urls.py
2
3from django.urls import path
4from . import views
5app_name = 'plot'
6urlpatterns = [
7 path('index/', views.MoneyListView.as_view(), name='index'),
8]
money_list.html
HTML
1{% extends 'base.html' %}
2{% block content %}
3<h1>Graph</h1>
4
5<img src="data:image/png;base64, {{ graph | safe }} " alt="">
6
7<table>
8 <tr>
9 <th></th>
10 <th>Taro</th>
11 <th>Jiro</th>
12 <th>Koki</th>
13 <th>Kaze</th>
14
15 </tr>
16 <tr>
17 <td>payment</td>
18 <td>{{ pay_taro |floatformat:0 }}</td>
19 <td>{{ pay_jiro |floatformat:0 }}</td>
20 <td>{{ pay_koki |floatformat:0 }}</td>
21 <td>{{ pay_kaze |floatformat:0 }}</td>
22 </tr>
23 <tr>
24 <td>deficiency</td>
25 <td>{{ deficiency_taro |floatformat:0 }}</td>
26 <td>{{ deficiency_jiro |floatformat:0 }}</td>
27 <td>{{ deficiency_koki |floatformat:0 }}</td>
28 <td>{{ deficiency_kaze |floatformat:0 }}</td>
29 </tr>
30
31</table>
32{% endblock %}
ディレクトリ構成
text
1myapp/
2├ money_app/
3| ├ migrations/
4| ├ templates/
5| | ├ money_app/
6| | | └ money_list.html
7| | └ base.html
8| ├ admin.py
9| ├ apps.py
10| ├ models.py
11| ├ urls.py
12| └ views.py
13├ myapp/
14├ └・・・
15├ ・・・
16├ manage.py
17└ db.sqlite3