PythonのWebフレームワークDjangoでファイルの関係性を解説しながら、BMI計算アプリを作ってみる 〜その3〜

目次

Django

前回、BMI計算アプリのIndexページを表示するところまで解説しました。

そして今のディレクトリ構造はこんな感じ。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── templates
│   │   └── bmiapp
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

それでは今回はフォームを作るところから始めていきましょう。

/testapp2/bmiapp/forms.py(新規作成)

フォームを作るには/testapp2/bmiapp の下に「forms.py」というファイルを作成します。

そのファイルに使用するファイルを記述していきます。

from django import forms

class BMIForm(forms.Form):
    height = forms.IntegerField()
    weight = forms.IntegerField()

記述するのはこれだけ。

最初に「from django import forms」でフォームのライブラリを読み込みます。

そして呼び出すためのクラス名を「class BMIForm(forms.Form):」として記述。

最後の2行は使用するフォームを示しています。

もちろん使いたいフォームがもっとある場合はどんどん追加していきます。

この「forms.py」は/testapp2/bmiapp/views.py から読み込まれます。

ということで次に「views.py」を修正していきましょう。

/testapp2/bmiapp/views.py

ファイルの在処はこちらです。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── templates
│   │   └── bmiapp
│   │       └── index.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py  <ーこれ
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

変更前がこちら。

from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    params = {
        'title':'BMI APP'
    }
    return render(request, 'bmiapp/index.html', params)

変更後がこちら。

from django.shortcuts import render
from django.http import HttpResponse
from .forms import BMIForm

def index(request):
    params = {
        'title':'BMI APP',
        'forms':BMIForm(),
    }
    return render(request, 'bmiapp/index.html', params)

インポート文に「from .forms import BMIForm」とすることで、同じフォルダ内の「forms.py」の中のクラス「BMIForms」を呼び出しています。

そしてparamsに「’forms’:BMIForm(),」を追加して、HTML上に呼び出す準備をしています。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py <ーーーーーー|
│   ├── migrations      |
│   │   └── __init__.py   |
│   ├── models.py       | フォームの内容を呼び出し
│   ├── templates           |
│   │   └── bmiapp          |
│   │       └── index.html  |
│   ├── tests.py        |
│   ├── urls.py             |
│   └── views.py ーーーーーーー
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

次にindex.htmlを変更して、フォームを表示させてみましょう。

/testapp2/bmiapp/templates/bmiapp/index.html

フォームを表示させるため「index.html」をいじっていきます。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── migrations      
│   │   └── __init__.py   
│   ├── models.py       
│   ├── templates           
│   │   └── bmiapp          
│   │       └── index.html <ーこれ
│   ├── tests.py        
│   ├── urls.py             
│   └── views.py
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

元々のコードはこちら。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>Write code here!</p>
</body>
</html>

こう変更します。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <form action="{% url 'index' %}" method="post">
        {% csrf_token %}
        {{ forms }}
        <input type='submit' value="click">
    </form>
</body>
</html>

変更してフォームの記述を足したのはここです。

    <form action="{% url 'index' %}" method="post">
        {% csrf_token %}
        {{ forms }}
        <input type='submit' value="click">
    </form>

最初の「<form action=”{% url ‘index’ %}” method=”post”>」でこのフォームに値が入力され、Post(送信)されたときには、index.htmlに書かれたコードを実行するように書かれています。

「{% csrf_token %}」はボット対策。

「{{ forms }}」が「forms.py」に記載されたフォームの表示場所。

「<input type=’submit’ value=”click”>」はボタンがクリックされたときに値を送信するというボタンのコマンドです。

まず「index.html」が呼び出された時の情報のやりとりはこうです。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── migrations      
│   │   └── __init__.py   
│   ├── models.py       
│   ├── templates           
│   │   └── bmiapp          
│   │       └── index.html <ーー
│   ├── tests.py          | フォームを表示
│   ├── urls.py               |
│   └── views.py ーーーーーーーーー
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

送信ボタンが押された時のデータのやりとりはこうです。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── migrations      
│   │   └── __init__.py   
│   ├── models.py       
│   ├── templates           
│   │   └── bmiapp          
│   │       └── index.html ーーー
│   ├── tests.py          | 
│   ├── urls.py               | 入力された値を送信
│   └── views.py <ーーーーーーーー
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

ただ現状では値が入力され、送信されたとしても「views.py」内ではその値をどう扱うかは記述されていません。

ということで「views.py」にその動作を記述していきましょう。

/testapp2/bmiapp/views.py

「views.py」は先ほどもいじったので、ファイルの在処は分かっているかと思います。

さて今回はBMI計算アプリということで、BMIの計算方法を知っておく必要があります。

BMIの計算式は 体重(kg)➗ 身長(m) です。

ついでに適正体重は 身長(m) ✖️ 22 です。

これらをviews.pyに入れていくとこうなります。

from django.shortcuts import render
from django.http import HttpResponse
from .forms import BMIForm

def index(request):
    params = {
        'title':'BMI APP',
        'forms':BMIForm(),
    }
    if (request.method == 'POST'):
        height = int(request.POST['height'])
        weight = int(request.POST['weight'])

        params['bmi'] = weight / ((height/100) * (height/100))
        params['optimal'] = (height/100) * (height/100) * 22

    return render(request, 'bmiapp/index.html', params)

増えた最初の3行がindex.htmlから送られてきたデータの取り込み。

    if (request.method == 'POST'):
        height = int(request.POST['height'])
        weight = int(request.POST['weight'])

最初の「if (request.method == ‘POST’):」で、データがPOST(送信)されたというシグナルを受け取った場合と規定しています。

そして次の2文でheightとweightの値を受け取り、int型に変更しています。

        height = int(request.POST['height'])
        weight = int(request.POST['weight'])

そして次は受け取った値の加工。

        params['bmi'] = weight / ((height/100) * (height/100))
        params['optimal'] = (height/100) * (height/100) * 22

ここは普通のPythonの計算なので特に難しいことはないと思います。

ただ注意すべきは「params[‘bmi’]」と「params[‘optimal’]」というようにparamsにデータを渡していること。

なぜなら最後に表示を支持するこの一文。

return render(request, 'bmiapp/index.html', params)

最後に「params」をデータとして「index.html」に渡しているので、paramsに格納しておけば、「index.html」上で表示場所の指定をすることで表示ができるというわけです。

つまりこういうこと。

testapp2
├── bmiapp
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── migrations      
│   │   └── __init__.py   
│   ├── models.py       
│   ├── templates           
│   │   └── bmiapp          
│   │       └── index.html <ーー
│   ├── tests.py          | 
│   ├── urls.py               | 受け取った値を加工して、再度受け渡す
│   └── views.py ーーーーーーーーー
├── db.sqlite3
├── manage.py
└── testapp2
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

/testapp2/bmiapp/templates/bmiapp/index.html

今度は「index.html」上に先ほど計算したBMI値と適正体重を表示する場所を記述してやります。

細かいことはあとで修正することにして、とりあえず入力欄の下に表示してみましょう。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <form action="{% url 'index' %}" method="post">
        {% csrf_token %}
        {{ forms }}
        <input type='submit' value="click">
    </form>
    <p>{{bmi}}  {{optimal}}</p>
</body>
</html>

変更したのは</form>と</body>の間に一文入れたこと。

    </form>
    <p>{{bmi}}  {{optimal}}</p>
</body>

これでサーバーを起動し、「http://127.0.0.1:8000/bmiapp/」にアクセスしてみました。

そしてheightを170に、weightを60としてみました。

「click」を押してみるとこうなります。

小数点以下が大量に出てきて綺麗ではありませんが、とりあえず計算して表示をすることができました。

ただ計算後に入力した値が消えてしまうのも、どの値を入れたのか分からなくなってしまうので、よろしくありません。

さらにHeightとWeightの単位が書かれていないため、もしかしたら身長(Height)を1.7 (m)として入力してしまう人もいるかもしれませんし、体重(Weight)を60000 (g)としてしまう人もいるかもしれません。

そしてBMI値や適正体重は出てきたのですが、それがどれくらいいい値なのか、もしくは悪い値なのかこのままでは分かりません。

ということで次回からここら辺の課題をクリアしていきたいなと思います。

ではでは今回はこんな感じで。

よかったらシェアしてね!

コメント

コメントする

目次
閉じる