1
5

More than 3 years have passed since last update.

Djangoとビュー画面、データベースを紐付ける(初学者がどこまで理解できるか(4))

Last updated at Posted at 2019-10-14

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>形式で表示。
これでひとまず、「いつ、どの項目で、何を、いくらで」買ったかを、送信するページはできました。
スクリーンショット 2019-10-14 23.33.01.png

ビュー画面(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>内にデータを返すという内容です。
スクリーンショット 2019-10-14 23.37.17.png

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ルールがあるのかな?
また、整理できたら更新します。

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5