html経由なので、セキュリティー対策として、FLask-WTFormsを使います。
データベース操作は、FLASK-SQLAlchemyで記述していますが、他のDB言語にでも良いです。(SQLを直接でも、SQLALchemyなどのORMでも、ご自由にどうぞ)
尚、FLASKのアプリファイルは一括して1つのファイルにアプリファイルに書いています。分かり易いので。
今回のTIPは、データ内容を更新する場合、フィールドに、最初から修正対象のデータがインプット(プレ・ポピュレイティド)されているようにします。
ある種のplaceholderの値を動的に作成する感じです。 <submit>ではなく、<a href>を使うのがポイントです。
【参考】
もっと詳しく、各記述の理解をしたい場合、
Flask (1) WTForms でHTMLの入力フォームのセキュリティー対策
も、参考にしてみてください。
基本の構成
<1. データベースへの新規追加と一覧表示>
(ファイル構成)
--- tw_msg.py
|---templates/
|---message.html
◇tw.message.py
(tw_msg.py)
import os
from flask import Flask, flash,render_template, request,url_for, redirect
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length
app = Flask(__name__)
project_dir = os.path.dirname(os.path.abspath(__file__))
database_file = "sqlite:///{}".format(os.path.join(project_dir, "msg.db"))
app.config["SQLALCHEMY_DATABASE_URI"] = database_file
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] ='you-will-never-know'
db = SQLAlchemy(app)
#DB Model
class Tw_msg (db.Model):
__tablename__ = 'tw_msg'
id = db.Column(db.Integer, unique=True, primary_key=True)
time = db.Column(db.String(6))
message = db.Column(db.String(140))
hashtag =db.Column(db.String(140))
url = db.Column(db.String(140))
#WTF Model(入力フィールド定義)
class Message_Add(FlaskForm):
id = StringField('ID')
time = StringField('Time',
validators=[DataRequired(), Length(min=2, max=60)])
message = StringField('Message')
hashtag = StringField('Hashtag')
url = StringField('URL')
submit = SubmitField('Submit')
#ルーティングと処理
@app.route('/',methods=['GET', 'POST'])
def message():
db.create_all()
form = Message_Add()
#新規データ受付時処理
try:
if form.validate_on_submit():
message = Tw_msg(id= form.id.data, time = form.time.data, message = form.message.data , hashtag = form.hashtag.data, url = form.url.data )
db.session.add(message)
db.session.commit()
flash('New message has been created!', 'success')
return redirect(url_for('message'))
except:
flash('Failed at somewhere!', 'Unsuccess')
#登録データ一覧表示
messages = Tw_msg.query.all()
return render_template("message.html",form=form, messages=messages)
(message.html)
<body>
<!-- Flash Message -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<h3>新規追加</h3>
<div class="box1">
<form method="POST" action="{{ url_for('message')}}">
{{ form.hidden_tag() }} #これを忘れると、送信が受付られません。
<p>{{ form.time.label }} : {{ form.time(size=10) }}</p>
<p>{{ form.message.label }}: {{ form.message(size=100) }}</p>
<p>{{ form.hashtag.label}} : {{ form.hashtag(size=50) }}</p>
<p>{{ form.url.label}} : {{ form.url(size=100) }} </p>
<p>{{ form.submit() }}</p>
</form>
</div>
<h3>登録済メッセージ一覧</h3>
{% for message in messages %}
<div class="box1">
<p>id: {{message.id}}
Time: {{message.time}} :</p>
<p>Message: {{message.message }} :</p>
<p>Hashtag:{{message.hashtag}} </p>
<p>URL: {{message.url}}:</p>
<a href="{{ url_for('edit_message',message_id = message.id)}}">Update</a>
</div>
{% endfor %}
message.idで、リストからイテレイトして表示させた各レコードのうち、どれを選択したかを特定します。 Flask-wtfのform.submit( ) で、この種の、レコードを特定させるファンクションは供えられていないので、<a href=>のリンクで、URLを指定してeditファンクションにアクセスします。
この状態で 'Update'をクリックすると、
にアクセスすることになります。 ここは、後で綺麗にします。
<a href>タグでのアクセスになりますから、このリクエストは'GET'です。
(ファイル構成)
--- tw_msg.py
|---templates/
|---message.html
|---edit_message.html
(処理の流れ)
Step①: 最初のアクセスとして、message.htmlで一覧表示で、UPDATEをクリックすると
<a href="{{ url_for('edit_message',message_id = message.id)}}">Update</a>
で一緒に送られてくる、message.idを取得し、DBのQueryでレコードを特定
Step②:特定されたレコードの各要素を、FORMの値として代入し、form = form で、edit_message.htmlにpassして、表示させる。
Step③:edit_message.htmlで各form itemを修正し、submitボタンでsubmitされてくる値をDBに登録。
(tw_msg.py:該当部のみ記載)
@app.route("/<int:message_id>/edit", methods=['GET', "POST"])
def edit_message(message_id):
♯ ① 初回アクセス時に送信されてきたidで、対象のレコードを特定。
msg = Tw_msg.query.get(message_id)
form = Message_Add()
♯ ③ 表示された内容を変更し、データがsubmitされてきた時の処理。
if form.validate_on_submit():
msg.id = form.id.data
msg.time = form.time.data
msg.message = form.message.data
msg.hashtag = form.hashtag.data
msg.url = form.url.data
db.session.commit()
flash('Your post has been updated!', 'success')
return redirect(url_for('message'))
♯ ② 初回アクセス時。 データ・フォーム内に値を事前挿入(プレ・ポピュレイト)
elif request.method == 'GET':
form.id.data = msg.id
form.time.data = msg.time
form.message.data = msg.message
form.hashtag.data = msg.hashtag
form.url.data = msg.url
return render_template("edit_message.html",form=form)
edit_message.html
<form action="" method="post">
{{ form.hidden_tag() }}
<div class="box1">
<p>{{form.id.label}}:{{form.id()}}</p>
<p>{{form.time.label}}:{{form.time()}}</p>
<p>{{form.message.label}}:{{form.message()}}</p>
<p>{{form.hashtag.label}}:{{form.hashtag()}}</p>
<p>{{form.url.label}}:{{form.url()}}</p>
<p>{{ form.submit() }}</p>
</form>
</div>
*action=" "を空欄にしておくのがミソ。 url_for などで特定しない。 ここが分からなくて、かなり苦労した。
< 3. 登録済みデータベースの削除>
これは簡単。 一覧ページに以下のようにDeleteボタンを作ります。
<message.htm>
<a href="{{ url_for('edit_message',message_id = message.id)}}">Update</a>
# Deleteを追加
<a href="{{ url_for('delete_message',message_id = message.id)}}">Delete</a>
<tw_msg.py>
# Delete処理を追加
@app.route("/<int:message_id>/delete", methods=['GET', "POST"])
def delete_message(message_id):
msg = Tw_msg.query.get_or_404(message_id)
db.session.delete(msg)
db.session.commit()
flash('Your post has been deleted!', 'success')
return redirect(url_for('message'))
これで削除もできるようになりました。
以上です。
以下、全体。
tw_msg.py
import os
from flask import Flask, render_template,url_for,flash, redirect, request
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length
app = Flask(__name__)
project_dir = os.path.dirname(os.path.abspath(__file__))
database_file = "sqlite:///{}".format(os.path.join(project_dir, "msg.db"))
app.config["SQLALCHEMY_DATABASE_URI"] = database_file
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] ='you-will-never-know'
db = SQLAlchemy(app)
#DB Model
class Tw_msg (db.Model):
__tablename__ = 'tw_msg'
id = db.Column(db.Integer, unique=True, primary_key=True)
time = db.Column(db.String(6))
message = db.Column(db.String(140))
hashtag =db.Column(db.String(140))
url = db.Column(db.String(140))
#WTF Model(入力フィールド定義)
class Message_Add(FlaskForm):
id = StringField('ID',validators=[DataRequired(), Length(min=1, max=3) ])
time = StringField('Time',
validators=[DataRequired(), Length(min=2, max=60) ])
message = StringField('Message')
hashtag = StringField('Hashtag')
url = StringField('URL')
submit = SubmitField('Submit')
#ルーティングと処理
@app.route('/',methods=['GET', 'POST'])
def message():
db.create_all()
form = Message_Add()
#新規データ受付時処理
try:
if form.validate_on_submit():
message = Tw_msg( time = form.time.data, message = form.message.data ,
hashtag = form.hashtag.data, url = form.url.data )
db.session.add(message)
db.session.commit()
flash('New message has been created!', 'success')
return redirect(url_for('message'))
except:
flash('Failed at somewhere!', 'Unsuccess')
#登録データ一覧表示
messages = Tw_msg.query.all()
return render_template("message.html",form=form, messages=messages)
@app.route("/<int:message_id>/edit", methods=['GET', "POST"])
def edit_message(message_id):
msg = Tw_msg.query.get(message_id)
form = Message_Add()
if form.validate_on_submit():
msg.id = form.id.data
msg.time = form.time.data
msg.message = form.message.data
msg.hashtag = form.hashtag.data
msg.url = form.url.data
db.session.commit()
flash('Your post has been updated!', 'success')
return redirect(url_for('message'))
elif request.method == 'GET':
form.id.data = msg.id
form.time.data = msg.time
form.message.data = msg.message
form.hashtag.data = msg.hashtag
form.url.data = msg.url
#return "I'm doin' fine."
return render_template("edit_message.html",form=form)
@app.route("/<int:message_id>/delete", methods=['GET', "POST"])
def delete_message(message_id):
msg = Tw_msg.query.get_or_404(message_id)
db.session.delete(msg)
db.session.commit()
flash('Your post has been deleted!', 'success')
return redirect(url_for('message'))
if __name__ == "__main__":
app.run()
<message.html>
<html>
<head>
<style type="text/css">
.box1 {
padding: 0.5em 1em;
margin: 2em 0;
font-weight: bold;
color: #6091d3;/*文字色*/
background: #FFF;
border: solid 3px #6091d3;/*線*/
border-radius: 10px;/*角の丸み*/
}
.box2 p {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<!-- Flash Message -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<h3>新規追加</h3>
<div class="box1">
<form method="POST" action="{{ url_for('message')}}">
{{ form.hidden_tag() }}
<p>{{ form.id.label }} : {{ form.id(size=3) }}</p>
<p>{{ form.time.label }} : {{ form.time(size=10) }}</p>
<p>{{ form.message.label }}: {{ form.message(size=100) }}</p>
<p>{{ form.hashtag.label}} : {{ form.hashtag(size=50) }}</p>
<p>{{ form.url.label}} : {{ form.url(size=100) }} </p>
<p>{{ form.submit() }}</p>
</form>
</div>
<h3>登録済メッセージ一覧</h3>
{% for message in messages %}
<div class="box1">
<p>id: {{message.id}}
Time: {{message.time}} :</p>
<p>Message: {{message.message }} :</p>
<p>Hashtag:{{message.hashtag}} </p>
<p>URL: {{message.url}}:</p>
<a href="{{ url_for('edit_message',message_id = message.id)}}">Update</a>
<a href="{{ url_for('delete_message',message_id = message.id)}}">Delete</a>
delete_message
</div>
{% endfor %}
</body>
</html>
<edit_message.html>
<html>
<head>
<style type="text/css">
.box2 {
padding: 0.5em 1em;
margin: 2em 0;
font-weight: bold;
color: #6091d3;/*文字色*/
background: #FFF;
border: solid 3px #6091d3;/*線*/
border-radius: 10px;/*角の丸み*/
}
.box2 p {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<form action="" method="post">
{{ form.hidden_tag() }}
<div class="box1">
<p>{{form.id.label}}:{{form.id()}}</p>
<p>{{form.time.label}}:{{form.time()}}</p>
<p>{{form.message.label}}:{{form.message(size=100)}}</p>
<p>{{form.hashtag.label}}:{{form.hashtag(size=30)}}</p>
<p>{{form.url.label}}:{{form.url(size=30)}}</p>
<p>{{ form.submit() }}</p>
</form>
</div>
</body>
</html>
0 件のコメント:
コメントを投稿