Flaskでフラッシュメッセージとデータの格納を組み合わせて実行したときのエラーについて
Flaskで
・フラッシュメッセージを出す
・フォームに入力された値をデータベースに格納してWebページに表示
それぞれは動作するのですが、組み合わせるとエラーが起きます。
エラー文
secret key
に関してのエラー文のようですが、検索しても修正方法がわからず困っています。
Flaskの公式ドキュメント・Message Flashingにシークレットキーに関する記述がありましたが、この例ではログイン実装などをしているため、今回のような例でもなぜ必要なのかわかりません。
・ターミナル
フォームの記入/未記入にかかわらず、エラー文は同じです。
(<class 'RuntimeError'>, RuntimeError('The session is unavailable because no secret key was set.
Set the secret_key on the application to something unique and secret.',), <traceback object at 0x10d2cf3c8>)
・ブラウザでの動作
フォームへの記入/無記入関係なく、Createボタンを押すと
Bad Request
The browser (or proxy) sent a request that this server could not understand.
となります。
if error:
abort (400)
フォームが未記入の場合、上記の部分でflash("テキストを入力してください", "failed")
とした方がいいのかと考えましたが、フォームの記入/未記入にかかわらず、エラー文が同じなため、解決方法がわからない状態です。
実行プログラム
app.py
from flask import Flask, flash, render_template, request, redirect, url_for, abort, jsonify
from flask_sqlalchemy import SQLAlchemy
import sys
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://username@localhost:5432/todoappbegin'
db = SQLAlchemy(app)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
def __repr__(self):
return f'<Todo {self.id}{self.description}>'
db.create_all()
#テキストが入力されていたら、データベースに格納し、HTMLページに表示
@app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
description = request.form['description']
todo = Todo(description=description)
#テキストが入力されていたら
if description:
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
flash("投稿に成功しました", "success")
elif texts == "":
flash("テキストを入力してください", "failed")
db.session.rollback()
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if error:
abort (400)
else:
return jsonify(body)
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all())
Index.html
<html>
<head>
<title>Todo App</title>
<style>
#error {
display: none;
}
</style>
</head>
<body>
<div id="error" class="hidden">Something went wrong!</div>
<form id="form" method="post" action="/texts/create">
<input type="text" id="username" name="username">
<input type="text" id="texts" name="texts" />
<input type="submit" value="Create" />
</form>
<ul id="username">
{% for d in data %}
<li>{{d.username}}</li>
{% endfor %}
</ul>
<ul id="texts">
{% for d in data %}
<li>{{ d.texts }}</li>
{% endfor %}
</ul>
<script>
const nmInput = document.getElementById('username')
const descInput = document.getElementById('texts');
document.getElementById('form').onsubmit = function(e) {
e.preventDefault();
const nm = nameInput.value;
const desc = descInput.value;
descInput.value = '';
fetch('/texts/create', {
method: 'POST',
body: JSON.stringify({
'username':nm,
'texts': desc,
}),
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(jsonResponse => {
console.log('response', jsonResponse);
li = document.createElement('li');
li.innerText = nm;
li.innerText = desc;
document.getElementById('usernames').appendChild(li);
document.getElementById('texts').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
document.getElementById('error').className = '';
})
}
</script>
</body>
</html>
組み合わせたそれぞれのプログラム
フラッシュメッセージの表示は
Flaskでフラッシュメッセージを表示する方法
というQuiitaの記事のプログラムの動作を確認しました。
また入力したデータをデータベースに格納・Webページに表示するプログラムは以下です。
HTMLファイルは現在実行しているものと同じです。
from flask import Flask, render_template, request, redirect, url_for, abort, jsonify
from flask_sqlalchemy import SQLAlchemy
import sys
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://username@localhost:5432/todoappbegin'
db = SQLAlchemy(app)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
def __repr__(self):
return f'<Todo {self.id}{self.description}>'
db.create_all()
@app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
description = request.form['description']
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if error:
abort (400)
else:
return jsonify(body)
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all())
実行環境
Python 3.6.0
Flask 1.1.1
Sqlalchemy 1.3.10
psql (PostgreSQL) 11.5
ブラウザ Google Chrome