家計簿アプリの続きです。これからグラフを表示することを考えて、ユーザー入力欄に支出のカテゴリーを選択する欄を追加します。
モデルにカテゴリーを追加する。
モデルを下のように書き換えます。
money/models.py
from django.db import models # Create your models here. class Money(models.Model): use_date = models.DateField('日付') detail = models.CharField(max_length=200) cost = models.IntegerField(default=0) category = models.CharField(max_length=10) # <- 追加 def __str__(self): return self.detail + ' ¥' + str(self.cost)
フォームを変更する
モデルに対応して、フォームを変更します。
money/forms.py
from django import forms from .models import Money class SpendingForm(forms.Form): choices = ( ('食費', '食費'), ('学費', '学費'), ('交通費', '交通費'), ('趣味', '趣味'), ) use_date = forms.DateTimeField(label='日付') cost = forms.IntegerField(label='金額') detail = forms.CharField( max_length=200, label='用途' ) category = forms.ChoiceField(choices=choices, label='カテゴリー')
選択肢となるものをchoices
として最初に定義しています。('食費', '食費')などと書いているのは、データベースに登録されるときの名前と選択肢に表示される名前をそれぞれ表しています。
そして、フィールドとしては、ChoiceField
として追加しています。
ビューを変更する
送信ボタンが押されたときに受け取る値にもカテゴリーを追加します。
money/views.py
from django.shortcuts import render, redirect from django.utils import timezone import pytz import datetime from .models import Money from .forms import SpendingForm # 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 } 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)
ついでに、特定の月に使った全金額も計算してしまいました。
テンプレートを変更する
最後に、テンプレートを変更していきます。
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> <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> </body>
データベースを更新する
データベースのテーブル数を変えたので、データベースの更新を行わなくてはいけません。
python manage.py makemigrations
で更新しようとすると、次のような表示が出ます。
You are trying to add a non-nullable field 'category' to money without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit, and let me add a default in models.py Select an option:
何を言っているかというと、テーブル数増えたけど、今まで登録したデータのこの欄どうするの?ということです。1番を選択してデフォルト値を適当に設定してしまいます。
1を入力してエンターするとPythonが起動します。ここでは'食費'をデフォルト値にします。食費を入力してエンターを押すと、デフォルト値のセットが完了します。
Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now Type 'exit' to exit this prompt >>> '食費'
後は、データベースへ変更を反映します。
python manage.py migrate
これで完了です。