fujimonish
@fujimonish

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【初投稿】flaskでのリクエストエラーについて

解決したいこと

初投稿です。

python初学者で、flaskの学習のためwebサイト上を構築し簡単なform画面を作成している最中です。
form上でボタンを押下し、pyファイルから関数を呼びだしたいのですがにweb画面上に以下のメッセージが表示されエラーになってしまいます。

エラーメッセージ

Bad Request
The browser (or proxy) sent a request that this server could not understand.

以下、コード部分です

.html

<form method="post" action="{{url_for('register')}}">
    <ul>
        <li><p>名前:</p><input type="text" name="name"></li>
        <li><p>郵便番号:</p><input type="text" name="zip_code"value={{zip_code}}><input type="submit" name="serch" value="検索"></li>
        <li><p>住所:</p><input class="address" type="text" name="address" value={{address}}> </li>
        <li><p>テキスト欄:</p><textarea class="textarea" name="textarea" row="10" col="20"></textarea></li>
    </ul>
    <input type="submit" name="do_commit" value="登録">
</form>

.py

@app.route('/register',methods=["POST"])
def register():
    if request.form['do_commit']:
        ---処理---

--input type="submit" name="do_commit" value="登録"
この部分で生成した要素を押下した際にregisterを実行したいのですがエラーになってしまいます。

自分で試したこと

request.form.to_dict()を投げて要素を取得したところkey="do_commit"が抜けてきませんでした。
{'name': '', 'zip_code': '', 'serch': '検索', 'address': '', 'textarea': ''}
要素として認識していないようで
if request.form['do_commit']の部分でエラーになっているようです。

0

4Answer

formactionでエンドポイントを作って飛ばしてあげると
Method Not Allowed
The method is not allowed for the requested URL.
のエラーがでます。
flaskだとformのactionからしか飛ばせないんでしょうか?

1Like

Comments

  1. @fujimonish

    Questioner

    すいません。自己解決しました。
    formactionでエンドポイント作って関数処理紐づけたらうまくいきました!!

こちらの方でも実験してみました.以下再現したコードです.

templates/index.html
<!DOCTYPE html>
<html>
	<form method="post" action="{{ url_for('register') }}">
		<ul>
			<li><p>名前:</p><input type="text" name="name"></li>
			<li><p>郵便番号:</p><input type="text" name="zip_code" value={{ zip_code }}><input type="submit" name="search" value="検索"></li>
			<li><p>住所:</p><input class="address" type="text" name="address" value={{ addreess }}></li>
			<li><p>テキスト欄:</p><textarea class="textarea" name="textarea" row="10" col="20"></textarea></li>
		</ul>
		<input type="submit" name="do_commit" value="登録">
	</form>
</html>
main.py
from flask import Flask, render_template, url_for, request, jsonify

app = Flask(__name__)

@app.route('/')
def front():
	return render_template('index.html')

@app.route('/register', methods = ["POST"])
def register():
	print(request.form.to_dict())
	if request.form['do_commit']:
		print("internal do_commit")
		return jsonify(code = 200)
	
	return jsonify(code = 100)

if __name__ == "__main__":
	app.run(debug = True)

key="do_commit"が抜けてきませんでした。

この状態が再現されたのは,input要素を使っているところでエンターキーを押下した場合に生じる状態でした.

この部分で生成した要素を押下した際にregisterを実行したい

とのことでしたが,formの特性上,複数のsubmitがあるならば,最初が優先されるようです.

submit要素のボタン押下ではなくエンターキーを用いた方の押下の場合にこのようなエラーが起きるのではないでしょうか.証拠として,do_commitは飛ばせていませんが代わりにsearchをPOSTできていることがfujimonishさんの自分で試したことの欄にある

{'name': '', 'zip_code': '', 'serch': '検索', 'address': '', 'textarea': ''}

からもわかると思います.

ちなみに,エンターキー押下ではなく下部に表示されている登録ボタンをマウスで押下した場合,ちゃんと動作することが確認できました.

main.pyのログ
{'name': 'hoge poge', 'zip_code': '1000001', 'address': 'Tokyo', 'textarea': 'Qiita question-feed', 'do_commit': '登録'}
internal do_commit
127.0.0.1 - - [30/Jan/2022 15:20:09] "POST /register HTTP/1.1" 200 -

そしてfujimonishさんのようにsearchの項はありません.

解決案

郵便番号から住所を検索したいとお見受けします.普通,RESTful APIの設計思想上/registerに2つの機能を持たせるのは良くなさそうなのですが,この記述で進む場合は以下のように修正する必要があります.

改善案
- if request.form['do_commit']:
+ if request.form.get('do_commit', None):

その上で,do_commitを扱う処理の下ぐらいに

if request.form.get('search', None):

というようにしてzip_codeからaddressに変換する処理を設ければ良いのではないでしょうか.
Pythonでは,辞書オブジェクトにkeyが存在しないことを想定して,dict.get(key, default)のような記述が可能です.keyが存在しなければdefaultに設定した値を返します.上記ではNoneを入れましたがif文の中に入らなければ良いのでFalseでも動きます.

0Like

ありがとうございます。
やりたいこととしては
1 検索ボタンを押したときは郵便番号から住所を返す関数を実行←こちらはうまく行っています
2登録ボタンを押したときはフォーム内の名前や住所、郵便番号、コメントをdb内のテーブルにinsertする
です。

1を実行してフォーム内に値を揃えた上で2で登録するイメージで考えており、同一フォーム内にsubmitを複数配置しているのですべてregister内で処理をかくつもりでした。
機能を別関数で分割したほうが良いのであればhtml側を書き直したほうが良いのですかね

0Like

submitにはformactionが使えますので,検索ボタンでは郵便番号から住所に変換するエンドポイントを新しく作って指定してあげるだけで良いと思います.

0Like

Your answer might help someone💌