コンテンツにスキップ

第8章 データべースの検索

1 GETでの受け取り

検索のようなデータベースの変更をともなわない処理は通常はPOSTでは作らずGETで作ります。なぜなら、GETでの送信は入力内容がURLに含まれるからです。これにより、再度そのURLにアクセスすれば検索結果が再現できます。

slist.html に検索フォームをmethod="get"で作成します。

<form action="/search" method="get" >
    <input type="text" name="word">
    <input type="submit" value="検索">
</form>

検索語を入力するテキストボックスにwordという名前を付けています。 hanbai.pyのほうではこれを/searchで受け取るsearch関数を作成します。

@app.get('/search')
def search():
    word = request.args['word']

    rows = Shouhin.query.filter(Shouhin.sname.contains(word)).all()
    return render_template('hanbai/slist.html', rows=rows)

GETでの送信のため、検索語を受け取っているところを request.form ではなく request.args で行っています。 検索結果を slist.html で表示します。

これによりGETでの検索が出来ます。例えば検索語に「ご」を入力したら、検索結果のURLは以下のようになるはずです。

http://127.0.0.1:5000/search?word=

このようにURLに入力内容を含めて送信するのがGETです。このため、GETでフォームを作成した場合、その入力内容をURLで再現することが出来ます。これにより、結果の共有や再現が容易になります。

通常、検索などのデータベースの変更を行わない処理はGETで作成します。しかし、パスワードの入力など、容易に再現されては困るものはPOSTで行います。

2 検索語の反映

現状では何を入力してこの検索結果になったかが、わかりません。そこで、hanbai.pyのsearch関数から、検索語をword=wordで送るようにします。

return render_template('hanbai/slist.html', rows=rows,word=word)

これを検索フォームに反映させます。name="word"のテキストボックスにvalue属性でwordを表示するようにします。

<input type="text" name="word" value="{{word}}" >

3 検索結果が無い場合

現状では検索結果が0件の場合、表が見出しだけ出てきて何が起こったかがよく分からない状態です。検索結果が0件の場合、表の見出しは表示せず、代わりに「検索対象がありません」などのメッセージを表示した方が良いでしょう。

このように条件によって表示を切り替えるためにテンプレート内でif文を使うことが出来ます。{% if 条件式 %}でif文を書きます。書き方はpythonと基本的には同じですが、条件式やelseの終わりに: は書かず、最後に endif を書きます。

{% if rows %}
<table> 
    <tr><th>商品ID</th><th>商品名</th><th>単価</th></tr>
    {% for r in rows %}
        <tr>
        <td>{{r.sid}}</td>
        <td>{{r.sname}}</td>
        <td>{{r.tanka}}</td>
        <td><a href="/uriage/{{r.sid}}">売上</a></td>
        <td><a href="/del/{{r.sid}}">削除</a></td>
        <td><a href="/update/{{r.sid}}">変更</a></td>
        </tr>
    {% endfor %}
</table>
{% else %}
    <p>検索対象がありません</p>
{% endif  %}

4 結合して検索

現在の売上一覧 /ulist では商品IDは表示されていますが、商品名は表示されていません。なぜなら売上テーブルには商品IDはあっても商品名は無いからです。商品名は商品テーブルにあります。

そこで、売上テーブルと商品テーブルを結合して表示してみます。まず、uslit関数では以下のようにして、Uriageテーブルから全行を検索しています。

rows = Uriage.query.all()

これを以下のように書き換えます。

rows = ( db.session.query(Uriage, Shouhin)
        .filter(Uriage.sid == Shouhin.sid )
        .all() )

長いため、改行して書けるように()で囲んでいます。 まず、db.session.query(Uriage, Shouhin)で2つのテーブルからの検索結果を得ます。これはクロス結合になりますので、filterでキーが一致するものだけを抜き出します。

これを ulist.html に結果を表示します。まず、for文ですが、rowsから取り出した結果は、UriageとShouhinの両方を返します。そこで、最初を既存の変数 r とし、次に s を追加します。

    {% for r,s in rows %}

そして、商品名は s.sname で表示できます(sidの列の次に追加します)。

    <td>{{s.sname}}</td>

thタグにも商品名を追加しておきます。