#Djangoで出金記録を投稿・表示してみます
Djangoでデータベース構築 (初学者がどこまで理解できるか(3)) の続きです。
今回は、お金を使った記録ができ、それが表示されるようにします。
<やりたいこと>
・いつ、何の用途に、何円使ったかを投稿 (データベースに保存)
・用途毎に記録を表示 (HTMLのテーブル表示)
<次回以降にやりたいこと>
・レイアウトの整理
・ソートなど機能を持たせること
->CSSやJavaScriptの実装かな??
データベースの整理
#### practice/myapplication/models.py
from django.db import models
class Payment(models.Model):
PAYMENT_CHOICES = (
('Food', '食費'),
('Clothes', '衣類'),
('Other', 'その他'),
)
payment_date = models.DateField(blank=True)
payment_type = models.CharField(max_length=50, choices=PAYMENT_CHOICES, blank=True)
payment_name = models.CharField(max_length=50, blank=True)
payment_price = models.IntegerField(blank=True)
# 管理画面(admin)で、文字列表示したいためで、特になくても良い。
def __str__(self):
return self.payment_name
データベースへのテーブルとして用意したのは、1種類Payment
だけです。
その中に、日付:payment_date
、項目:payment_type
、品目:payment_name
、金額:payment_price
の列(Field)を用意しました。
blank=True
:入力漏れがあるとエラーにする
choices
:選択形式にする
これで、データベースとしては「いつ、どの項目で、何を、いくらで」買ったか記録するテーブルの形は完了です。
ユーザーからデータベースへ書き込むフォームを用意
#### practice/myapplication/forms.py
# 新しくファイルを作る必要があります
from django import forms
from .models import Payment
class PostForm(forms.ModelForm):
# ModelFormクラスを継承。データベースに保存するには、Metaクラスが必要
class Meta:
# models.pyの使用したいクラス(Model)と、Fieldを記載
model = Payment
fields = ('payment_date', 'payment_type', 'payment_name', 'payment_price')
forms.py
は自動で生成されないため、ファイルを作成する必要があります。
Meta
クラスに関しては、調べてみても今のところ、データベースに保存するために必要なものとしか理解できておらず、ここについては追々認識を深めます。
確かに、Metaクラスなしで、動作はしませんでした。。。
ビュー画面への出力内容を用意
from django.shortcuts import render, redirect
from django.views.generic import FormView
from .forms import PostForm
from .models import Payment
# 必要ないですが"Hello world"表示画面です。
def index(request):
return render(request, 'myapplication/index.html')
# 出金記録の投稿画面です
class PostView(FormView):
template_name = 'myapplication/post.html'
form_class = PostForm
def form_valid(self, form_class):
form_class.save()
return redirect('myapplication:payment_result')
# 出金記録の一覧表示画面です。
def payment_result(request):
food_list = Payment.objects.filter(payment_type='Food').order_by('payment_date')
clothes_list = Payment.objects.filter(payment_type='Clothes').order_by('payment_date')
other_list = Payment.objects.filter(payment_type='Other').order_by('payment_date')
context = {
'food_list' : food_list,
'clothes_list' : clothes_list,
'other_list' : other_list
}
return render(request, 'myapplication/payment_result.html', context)
・投稿画面について
FormView
クラスを継承しています。
この中のform_valid
関数を使用することで、フォームに入力して成功すれば次の処理に移る、という動作を実現しています。
ここでいう次の処理とは、form_class.save()
(データベースへの保存)と、payment_result.html
へのリダイレクトです。
・一覧画面について
出力は、models.py
で分けたchoices毎(項目毎)に出力します。
order_by('payment_date')
:日時が昇順になるよう指定しました。
context
は、HTML分に埋め込めるよう、render()で引き渡します。
ビュー画面(HTML)の設定 (投稿画面)
<!-- practice/myapplication/templates/myapplication/post.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>入力画面</h2>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" value="送信">Go</button>
</form>
</body>
</html>
{% csrf_token %}
:脆弱性対策のために記載。
{{ form.as_p }}
:先に設定したformを、<p>形式で表示。
これでひとまず、「いつ、どの項目で、何を、いくらで」買ったかを、送信するページはできました。
ビュー画面(HTML)の設定 (一覧画面)
<!-- myapplication/templates/myapplication/payment_result.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h3>食費</h3>
<table>
<tr>
<th>日付</th>
<th>項目</th>
<th>購入品</th>
<th>金額(円)</th>
</tr>
{% if food_list %}
{% for f in food_list %}
<tr>
<td>{{ f.payment_date }}</td>
<td>{{ f.payment_type }}</td>
<td>{{ f.payment_name }}</td>
<td>{{ f.payment_price }}</td>
</tr>
{% endfor %}
{% endif %}
</table>
----------------------------------------
<h3>衣類</h3>
<table>
<tr>
<th>日付</th>
<th>項目</th>
<th>購入品</th>
<th>金額(円)</th>
</tr>
{% if clothes_list %}
{% for c in clothes_list %}
<tr>
<td>{{ c.payment_date }}</td>
<td>{{ c.payment_type }}</td>
<td>{{ c.payment_name }}</td>
<td>{{ c.payment_price }}</td>
</tr>
{% endfor %}
{% endif %}
</table>
----------------------------------------
<h3>その他</h3>
<table>
<tr>
<th>日付</th>
<th>項目</th>
<th>購入品</th>
<th>金額(円)</th>
</tr>
{% if other_list %}
{% for f in other_list %}
<tr>
<td>{{ f.payment_date }}</td>
<td>{{ f.payment_type }}</td>
<td>{{ f.payment_name }}</td>
<td>{{ f.payment_price }}</td>
</tr>
{% endfor %}
{% endif %}
</table>
----------------------------------------
</body>
</html>
簡単にまとめると、各***_listがviews.py
にあるなら、<td>内にデータを返すという内容です。
URLを紐付けます。admin設定も更新します
#### practice/myapplication/urls.py
from django.urls import path
from . import views
app_name = 'myapplication'
urlpatterns = [
path('', views.index, name='index'),
# クラス(PostView)を使用した、post/へのpathのみ、as_view関数を使用しています。
path('post/', views.PostView.as_view(), name='post'),
path('payment_result/', views.payment_result, name='payment_result'),
]
#### practice/myapplication/admin.py
from django.contrib import admin
from .models import Payment
admin.site.register(Payment)
これで準備ができました。最後にデータベースの更新と、開発サーバーを起動します。
ブラウザで、post/と、payment_result/にアクセスすると、先のHTMLが表示されます。
#### practice/
$ python manage.py makemigrations myapplication
$ python manage.py migrate
$ python manage.py runserver
さいごに
データベースへの入力・更新・出力、どうするのか最初全くわかりませんでしたが、forms.py、大変便利な機能だと思いました。
次は体裁を整えていきたいと思います。
CSSやJavascriptを使うかなと思っていますが、反映の仕方とかDjangoルールがあるのかな?
また、整理できたら更新します。