Django
前回、2ページ間で値を受け渡しすることで、足し算テストアプリの基本を作成しました。
ただ前回はあくまでも基本を作成しただけで、問題が1問しかありません。
そこで今回は問題を10問まで増やし、その上でレイアウトを整えてきたいと思います。
しかし足し算テストアプリは問題を表示するindex.htmlと答え合わせを表示するanswercheck.htmlの2ページありますので、今回はindex.htmlに絞って修正していきましょう。
ということで今回修正するファイルは以下の3つです。
- /webapp/tashizan1/forms.py
- /webapp/tashizan1/views.py
- /webapp/tashizan1/templates/tashizan1/index.html
webapp
├── ...
└── tashizan1
├── __init__.py
├── admin.py
├── apps.py
├── forms.py <- これ
├── migrations
│ └── __init__.py
├── models.py
├── templates
│ └── tashizan1
│ ├── answercheck.html
│ └── index.html <- これ
├── tests.py
├── urls.py
└── views.py <- これ
/webapp/tashizan1/forms.py
まずは解答欄となるフォームを増やす必要があるので、forms.pyを修正します。
ここは特に難しいことはなく、単純に前回作成したフォームをコピーし、名前を少し変えてやるだけです。
from django import forms
class Tashizan1Form(forms.Form):
answer0 = forms.IntegerField(min_value=0)
answer1 = forms.IntegerField(min_value=0)
answer2 = forms.IntegerField(min_value=0)
answer3 = forms.IntegerField(min_value=0)
answer4 = forms.IntegerField(min_value=0)
answer5 = forms.IntegerField(min_value=0)
answer6 = forms.IntegerField(min_value=0)
answer7 = forms.IntegerField(min_value=0)
answer8 = forms.IntegerField(min_value=0)
answer9 = forms.IntegerField(min_value=0)
一応、プログラムっぽくナンバリングは0から始めてみました。
/webapp/tashizan1/views.py
次にviews.pyのindex関数(def index(request):の部分)を修正していきますが、実は問題はここからです。
前回は問題が一つだけでしたので、「足される数」、「足す数」の両方をそれぞれ独自に作成していました。
params['q1a'] = random.randrange(10)
params['q1b'] = random.randrange(10)
ですが今回は問題数を10問にするということで、このまま進めていくと以下の点でプログラムが煩雑になります。
- views.pyのindex関数における問題の「足される数」「足す数」の作成
- index.htmlにおける「足される数」「足す数」の受け渡し
- views.pyのanswercheck関数での「足される数」「足す数」の読み込み
- views.pyのanswercheck関数での答え合わせ部分
足し算テストアプリのようなアプリなら、一度作成してしまえば、それほど修正することはないと思いますが、それでも全部一つずつダラダラと書くのはあまりスマートとは言えません。
ということでもう少し繰り返しを意識した形でプログラミングしていきたい、と考えて作成したindex関数がこちら。
def index(request):
params = definitions.readjson()
num_range = range(0,10)
params['qa'] = random.choices(num_range, k=10)
params['qb'] = random.choices(num_range, k=10)
params['forms'] = Tashizan1Form()
return render(request, 'tashizan1/index.html', params)
今回は「足される数(qa)」と「足す数(qb)」を取得するために、「random.randrange」ではなく、「random.choices」を作成することで複数個のランダムな数字をリストとして作成しています。
ただし「random.choices」を使うには、ランダムに要素を取ってくるリストが必要です。
そこで「num_range = range(0,10)」とすることで0から9の数字のリストを作成しています。
/webapp/tashizan1/templates/tashizan1/index.html
次にindex.htmlを編集していきます。
ここでも「{% for X in Y %}{% endofor %}」を使って繰り返しで表示したかったのですが、問題に対して解答欄のフォームをつけなければいけないため、別々に記述する必要があります。
ということでまず基本形としてはこんな感じにしてみました。
{% extends "basetemplates/base.html" %}
{% block title %}
<title>{{ title }}|足し算テスト1</title>
{% endblock %}
{% block content %}
<h1>足し算テスト1</h1>
<form action="{% url 'answercheck' %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col">
<p>1. {{ qa.0 }} + {{ qb.0 }} = {{ forms.answer0 }}</p>
<p>2. {{ qa.1 }} + {{ qb.1 }} = {{ forms.answer1 }}</p>
<p>3. {{ qa.2 }} + {{ qb.2 }} = {{ forms.answer2 }}</p>
<p>4. {{ qa.3 }} + {{ qb.3 }} = {{ forms.answer3 }}</p>
<p>5. {{ qa.4 }} + {{ qb.4 }} = {{ forms.answer4 }}</p>
<p>6. {{ qa.5 }} + {{ qb.5 }} = {{ forms.answer5 }}</p>
<p>7. {{ qa.6 }} + {{ qb.6 }} = {{ forms.answer6 }}</p>
<p>8. {{ qa.7 }} + {{ qb.7 }} = {{ forms.answer7 }}</p>
<p>9. {{ qa.8 }} + {{ qb.8 }} = {{ forms.answer8 }}</p>
<p>10. {{ qa.9 }} + {{ qb.9 }} = {{ forms.answer9 }}</p>
{% for qa_val in qa %}
<input type='hidden' name='qa' value={{qa_val}}>
{% endfor %}
{% for qb_val in qb %}
<input type='hidden' name='qb' value={{qb_val}}>
{% endfor %}
</div>
</div>
<p style="margin:2rem 0rem 0rem 0rem;"></p>
<input type='submit' value="答え合わせ">
</form>
{% endblock %}
ここで重要なのは「{{ qa.0 }}」という表記です。
先ほど足される数である「qa」と足す数である「qb」を数字のリストとして作成しました。
そのようなリストからインデックス番号を使って要素をHTML上で取得する記述が先ほどの「{{ qa.0 }}」という表記になります。
つまり「{{ qa.0 }}」では「リストqaの0番目の要素」を取得しているというわけです。
今回の場合、「qa」と「qb」はリストですが、リストの状態のまま次のページに受け渡すことはできません。
つまりこういう記述はできないということ。
<input type='hidden' name='qa' value={{qa}}>
リストとして次のページに受け渡しをしたい場合、「{{% for X in Y%}}{{% endfor %}}」を使って、要素を一つずつ取り出し、inputタグに追加していきます。
{% for qa_val in qa %}
<input type='hidden' name='qa' value={{qa_val}}>
{% endfor %}
{% for qb_val in qb %}
<input type='hidden' name='qb' value={{qb_val}}>
{% endfor %}
そしてviews.pyで次のページの処理(つまりanswercheck関数)では、「request.POST.getlist(‘X’)」といった感じでリストとして取得できます。
取得に関しては次回再度出てきますので、その際にも解説します。
これで一度サーバーを起動し、どのような表示になるか見てみましょう。
確かに問題が10問、バラバラの数字で出てきました。
なかなか良さそうな気もしますが、ここからレイアウトや表示を調整していきましょう。
レイアウトの調整
まず気になったのが、問10の部分です。
10問目だけナンバリングが2桁となってしまうので、問題の頭がずれてしまっています。
そこでこのズレを起こさないようテーブルを使って並べていきます。
{% extends "basetemplates/base.html" %}
{% block title %}
<title>{{ title }}|足し算テスト1</title>
{% endblock %}
{% block content %}
<h1>足し算テスト1</h1>
<form action="{% url 'answercheck' %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col">
<table>
<tr><td>1.</td><td>{{ qa.0 }} + {{ qb.0 }} = {{ forms.answer0 }}</td></tr>
<tr><td>2.</td><td>{{ qa.1 }} + {{ qb.1 }} = {{ forms.answer1 }}</td></tr>
<tr><td>3.</td><td>{{ qa.2 }} + {{ qb.2 }} = {{ forms.answer2 }}</td></tr>
<tr><td>4.</td><td>{{ qa.3 }} + {{ qb.3 }} = {{ forms.answer3 }}</td></tr>
<tr><td>5.</td><td>{{ qa.4 }} + {{ qb.4 }} = {{ forms.answer4 }}</td></tr>
<tr><td>6.</td><td>{{ qa.5 }} + {{ qb.5 }} = {{ forms.answer5 }}</td></tr>
<tr><td>7.</td><td>{{ qa.6 }} + {{ qb.6 }} = {{ forms.answer6 }}</td></tr>
<tr><td>8.</td><td>{{ qa.7 }} + {{ qb.7 }} = {{ forms.answer7 }}</td></tr>
<tr><td>9.</td><td>{{ qa.8 }} + {{ qb.8 }} = {{ forms.answer8 }}</td></tr>
<tr><td>10.</td><td>{{ qa.9 }} + {{ qb.9 }} = {{ forms.answer9 }}</td></tr>
</table>
{% for qa_val in qa %}
<input type='hidden' name='qa' value={{qa_val}}>
{% endfor %}
{% for qb_val in qb %}
<input type='hidden' name='qb' value={{qb_val}}>
{% endfor %}
</div>
</div>
<p style="margin:2rem 0rem 0rem 0rem;"></p>
<input type='submit' value="答え合わせ">
</form>
{% endblock %}
これを表示してみるとこうなります。
ちゃんと問題の頭が揃いました。
次に数字のフォントが数学的に綺麗ではないので、Mathjaxを使って綺麗な表示に変えていきます。
ちなみに3PySci-Appの場合は、basetemplatesのheaderにMathJaxのスクリプトを挿入してありますので、index.htmlには挿入しません。
MathJaxの記述の仕方としては「\(数式\)」でした。
またMacOSの場合、「\(バックスラッシュ)」の入力方法は「option + ¥ ()」です。
ということでこんな感じになります。
{% extends "basetemplates/base.html" %}
{% block title %}
<title>{{ title }}|足し算テスト1</title>
{% endblock %}
{% block content %}
<h1>足し算テスト1</h1>
<form action="{% url 'answercheck' %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col">
<table>
<tr><td>\(1.\)</td><td>\({{ qa.0 }} + {{ qb.0 }} = \){{ forms.answer0 }}</td></tr>
<tr><td>\(2.\)</td><td>\({{ qa.1 }} + {{ qb.1 }} = \){{ forms.answer1 }}</td></tr>
<tr><td>\(3.\)</td><td>\({{ qa.2 }} + {{ qb.2 }} = \){{ forms.answer2 }}</td></tr>
<tr><td>\(4.\)</td><td>\({{ qa.3 }} + {{ qb.3 }} = \){{ forms.answer3 }}</td></tr>
<tr><td>\(5.\)</td><td>\({{ qa.4 }} + {{ qb.4 }} = \){{ forms.answer4 }}</td></tr>
<tr><td>\(6.\)</td><td>\({{ qa.5 }} + {{ qb.5 }} = \){{ forms.answer5 }}</td></tr>
<tr><td>\(7.\)</td><td>\({{ qa.6 }} + {{ qb.6 }} = \){{ forms.answer6 }}</td></tr>
<tr><td>\(8.\)</td><td>\({{ qa.7 }} + {{ qb.7 }} = \){{ forms.answer7 }}</td></tr>
<tr><td>\(9.\)</td><td>\({{ qa.8 }} + {{ qb.8 }} = \){{ forms.answer8 }}</td></tr>
<tr><td>\(10.\)</td><td>\({{ qa.9 }} + {{ qb.9 }} = \){{ forms.answer9 }}</td></tr>
</table>
{% for qa_val in qa %}
<input type='hidden' name='qa' value={{qa_val}}>
{% endfor %}
{% for qb_val in qb %}
<input type='hidden' name='qb' value={{qb_val}}>
{% endfor %}
</div>
</div>
<p style="margin:2rem 0rem 0rem 0rem;"></p>
<input type='submit' value="答え合わせ">
</form>
{% endblock %}
これを表示してみるとこうなります。
数字が丸くなり、綺麗な表記になりました。
最後に問題と答え合わせボタンを中央寄せにします。
ボタンに関しては「<p style=’text-align: center;’></p>」で囲ってやれば中央寄せになりますが、テーブルはそうはいきません。
テーブルの場合、Bootstrapを使っていれば「<table class=”mx-auto”>」で中央寄せをすることができます。
ということでこんな感じです。
{% extends "basetemplates/base.html" %}
{% block title %}
<title>{{ title }}|足し算テスト1</title>
{% endblock %}
{% block content %}
<h1>足し算テスト1</h1>
<form action="{% url 'answercheck' %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col">
<table class="mx-auto">
<tr><td>\(1.\)</td><td>\({{ qa.0 }} + {{ qb.0 }} = \){{ forms.answer0 }}</td></tr>
<tr><td>\(2.\)</td><td>\({{ qa.1 }} + {{ qb.1 }} = \){{ forms.answer1 }}</td></tr>
<tr><td>\(3.\)</td><td>\({{ qa.2 }} + {{ qb.2 }} = \){{ forms.answer2 }}</td></tr>
<tr><td>\(4.\)</td><td>\({{ qa.3 }} + {{ qb.3 }} = \){{ forms.answer3 }}</td></tr>
<tr><td>\(5.\)</td><td>\({{ qa.4 }} + {{ qb.4 }} = \){{ forms.answer4 }}</td></tr>
<tr><td>\(6.\)</td><td>\({{ qa.5 }} + {{ qb.5 }} = \){{ forms.answer5 }}</td></tr>
<tr><td>\(7.\)</td><td>\({{ qa.6 }} + {{ qb.6 }} = \){{ forms.answer6 }}</td></tr>
<tr><td>\(8.\)</td><td>\({{ qa.7 }} + {{ qb.7 }} = \){{ forms.answer7 }}</td></tr>
<tr><td>\(9.\)</td><td>\({{ qa.8 }} + {{ qb.8 }} = \){{ forms.answer8 }}</td></tr>
<tr><td>\(10.\)</td><td>\({{ qa.9 }} + {{ qb.9 }} = \){{ forms.answer9 }}</td></tr>
</table>
<input type='hidden' name='qa' value={{qa}}>
<input type='hidden' name='qb' value={{qb}}>
</div>
</div>
<p style="margin:2rem 0rem 0rem 0rem;"></p>
<p style='text-align: center;'><input type='submit' value="答え合わせ"></p>
</form>
{% endblock %}
表示してみるとこんな感じです。
もう少し問題のフォントサイズを大きくしてもいいかなと思いますが、なかなかいい感じなので、とりあえずはこのままにしておきましょう。
次回はviews.pyのanswercheck関数とanswercheck.htmlを修正していきましょう。
ではでは今回はこんな感じで。
コメント