もくじ
FlaskとSQLAlchemyをインストール
pip install Flask
pip install sqlalchemy
SQLAlchemyのメリット
- SQL文を書かなくてもよい
- 異なるデータベースに移行するとき(SQLiteからMYSQLなど)、変更が少なくてすむ
らしいのですが、正直よくわかりません。
ファイルの階層
addressbook-demo
| bookFlask.py
|
+---static
| +---css
| | skeleton.css
| |
| \---js
| ajaxzip3.js
| jquery-3.5.1.min.js
| jquery.autoKana.js
|
\---templates
check.html
index.html
resister.html
以上のように作成します。郵便番号から住所を自動入力するためにajaxzip3.js
を、名前のフリガナを自動入力するためにjquery.autoKana.js
を使用します。
skeleton.css
cssのことはよく分からないので、フレームワークのskeleton.css
を使います。
skeleton.cssのダウンロードは、こちら。
運用環境
セキュリティに詳しくないので、ローカル環境で運用します。
ロリポップ!やエックスサーバーで運用する場合は、以下の記事を参考にファイルを追加してください。
フォームの完成イメージ
このような入力フォームを作っていきます。

データベースを作成
ファイル名は、address.sqlite
テーブル名は、address
カラム名は、以下のように設定しています。
カラム名 | |
id | ID(プライマリーキー、自動入力) |
sei | 姓 |
mei | 名 |
sei_kana | 姓のフリガナ |
mei_kana | 名のフリガナ |
zip01 | 郵便番号 |
pref01 | 都道府県名 |
addr01 | 都道府県名以降の住所 |
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///address.sqlite'
db = SQLAlchemy(app)
class Addressbook(db.Model):
__tablename__ = 'address'
id = db.Column(Integer, primary_key = True, autoincrement = True)
sei = db.Column(String(10))
mei = db.Column(String(10))
sei_kana = db.Column(String(20))
mei_kana = db.Column(String(20))
zip01 = db.Column(String(8))
pref01 = db.Column(String(4))
addr01 = db.Column(String(60))
def __init__(self, sei, mei, sei_kana, mei_kana, zip01, pref01, addr01):
self.sei = sei
self.mei = mei
self.sei_kana = sei_kana
self.mei_kana = mei_kana
self.zip01 = zip01
self.pref01 = pref01
self.addr01 = addr01
db.create_all()
データベースが存在していないと、SQLiteでデータベースを作成します。
SQLAlchemyはよく分からないので、これが正解かわかりませんが、とりあえず動作しています。
作成されたデータベース
sqlite> .schema
CREATE TABLE address (
id INTEGER NOT NULL,
sei VARCHAR(10),
mei VARCHAR(10),
sei_kana VARCHAR(20),
mei_kana VARCHAR(20),
zip01 VARCHAR(8),
pref01 VARCHAR(4),
addr01 VARCHAR(60),
PRIMARY KEY (id)
);
render templateとjinja2で表示
bookFlask.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///address.sqlite'
db = SQLAlchemy(app)
class Addressbook(db.Model):
__tablename__ = 'address'
id = db.Column(Integer, primary_key = True, autoincrement = True)
sei = db.Column(String(10))
mei = db.Column(String(10))
sei_kana = db.Column(String(20))
mei_kana = db.Column(String(20))
zip01 = db.Column(String(8))
pref01 = db.Column(String(4))
addr01 = db.Column(String(60))
def __init__(self, sei, mei, sei_kana, mei_kana, zip01, pref01, addr01):
self.sei = sei
self.mei = mei
self.sei_kana = sei_kana
self.mei_kana = mei_kana
self.zip01 = zip01
self.pref01 = pref01
self.addr01 = addr01
db.create_all()
# 入力フォームのname属性をリスト化
name_att = ['sei','mei','sei_kana','mei_kana','zip01','pref01','addr01']
@app.route('/')
def index():
return render_template('index.html', name_att = name_att)
@app.route('/check', methods=['POST'])
def check():
# index.htmlのフォームから受け取るデータ用リストを作成
check_list = []
# 受け取ったデータをリストに追加
for att in name_att:
check_list.append(request.form.get(att))
return render_template('check.html', check_list = check_list, name_att = name_att)
@app.route('/resister', methods=['POST'])
def resister():
# check.htmlのフォームから受け取るデータ用リストを作成
resister_list = []
# 受け取ったデータをリストに追加
for att in name_att:
resister_list.append(request.form.get(att))
# データベースのカラムに受け取ったデータを入力
book = Addressbook(
sei = resister_list[0],
mei = resister_list[1],
sei_kana = resister_list[2],
mei_kana = resister_list[3],
zip01 = resister_list[4],
pref01 = resister_list[5],
addr01 = resister_list[6])
# データベースへの書込処理
db.session.add(book)
db.session.commit()
db.session.close()
return render_template('resister.html')
if __name__ == '__main__':
app.run()
index.html
- htmlには詳しくないので、VSCodeの!で作成されるデフォルトにコードを追加しています。
- cssは、フレームワークのskeleton.cssを使用しています。
- 後で変更しやすいように、name_attリストを受け取ってname属性に代入しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>住所録入力</title>
<script type="text/javascript" src="./static/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="./static/js/ajaxzip3.js"></script>
<script type="text/javascript" src="./static/js/jquery.autoKana.js"></script>
<script>
$(document).ready(function(){
$.fn.autoKana('input[name="{{name_att[0]}}"]', 'input[name="{{name_att[2]}}"]', {katakana:true});
$.fn.autoKana('input[name="{{name_att[1]}}"]', 'input[name="{{name_att[3]}}"]', {katakana:true});
});
</script>
<link rel="stylesheet" type="text/css" href="./static/css/skeleton.css">
</head>
<body>
<form action="/check" method="POST">
<label>名前</label>
<input type="text" name="{{name_att[0]}}" placeholder="姓">
<input type="text" name="{{name_att[1]}}" placeholder="名">
<label>フリガナ</label>
<input type="text" name="{{name_att[2]}}">
<input type="text" name="{{name_att[3]}}">
<label>郵便番号(半角)</label>
<input type="text" name="{{name_att[4]}}" size="10" maxlength="8" onKeyUp="AjaxZip3.zip2addr(this,'','{{name_att[5]}}','{{name_att[6]}}');" placeholder="1234567">
<label>都道府県</label>
<input type="text" name="{{name_att[5]}}" size="20">
<label>以降の住所</label>
<input type="text" name="{{name_att[6]}}" size="40">
<input class="button-primary" type="submit" value="確認">
</form>
</body>
</html>
check.html
- 入力項目の確認画面は、jinja2のfor文を使って簡潔に表示しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登録確認</title>
<link rel="stylesheet" type="text/css" href="./static/css/skeleton.css">
</head>
<body>
<form action="/resister" method="POST">
{% for i in range(check_list | length) %}
{% if i == 0 or i == 2 %}
<input type="text" name="{{name_att[i]}}" value="{{check_list[i]}}" readonly>
{% elif i == 6 %}
<input type="text" name="{{name_att[i]}}" value="{{check_list[i]}}" readonly size="40"><br>
{% else %}
<input type="text" name="{{name_att[i]}}" value="{{check_list[i]}}" readonly><br>
{% endif %}
{% endfor %}
<button type="button" onclick="history.back()">戻る</button>
<input class="button-primary" type="submit" value="登録">
</form>
</body>
</html>
resister.html
- 登録完了と表示するだけのページです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登録完了</title>
</head>
<body>
登録完了
</body>
</html>
設置デモ
https://dattesar.com/addressbook-demo
データベース機能は削除してあります。ボタンを押してもデータは保存されません。