Flask を用いたデータベースアプリケーション制作 Part2

## 環境
macOS Catalina 10.15.1

## アプリケーションの実装内容
Flask の使い方を習得すべく3つのパートに分けた。

#### [Part1(前稿)](https://qiita.com/keisuke-ota/items/a4dd23fbb2c9b642bb2d)
* Web ブラウザの表示
* Templates フォルダの html ファイルと連結

#### Part2(本稿)
* データベース SQLite との連結
* Bootstrap を用いた画面表示

#### [Part3(次稿)](https://qiita.com/keisuke-ota/items/3661035948d3d65df520)
* POSTメソッドを用いた新規ユーザー登録

## Part2のフォルダ構成

[Part1](https://qiita.com/keisuke-ota/items/a4dd23fbb2c9b642bb2d)と同様に、全てのコードは run.py によって実行される。
run.py は Part1 と同じコードを使用した。

```
root
|--codes
| |--view.py
| |--templates
| | |--index2.html
|--models.py
|--run.py
|--test.db
```
## データベース SQLite との連結

view.py を以下に示す。
view.py 外部のデータベースに登録されている値を model.py の User クラスで定義することで連結している。

```python:view.py
# SQLAlchemy はデータベース(DB)を object のように扱えるライブラリである。
# 今回は DB との連結を担当する。
# models.py の User クラスで、どのような object として扱うかを決める。
from flask import Flask,render_template
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker 
from models import User

app = Flask(__name__)

# test.db (DB) と連結するための object である engine を作り、DB を session に代入する。
engine = create_engine('sqlite:///test.db')
session = sessionmaker(bind=engine)()

# /index2 へアクセスがあった場合に、 index2.html を返す。
@app.route("/index2")

# index2 関数を定義する。
# sessionn の全データを、User クラスで定義された object に代入し、users として返す。
# この users を html 内の users に代入する。

def index2():
	users = session.query(User).all()
	return render_template('index2.html', users=users)

if __name__ == "__main__":
    app.run(debug=True)
```
### SGLite によるデータベース構築

データベース管理システム sqlite で次の test.db を作成する。sqlite は、MAC にはデフォルトでインストールされている。

| id   | name | age  |
| ---- | ---- | ---- |
|0| Yoshizaki | 27 |
|1| Kikagaku | 2 |

まず次のコマンドを実施する。test.db が DB の名前である。

```terminal:ターミナル
sqlite3 test.db
```
すると``sqlite> ``という prefix が付与された対話モードに切り替わる。ここでは、DB の中に table を作ることができる。
まず id, name, age という3つの column からなる table を作る。

```terminal:ターミナル
create table users(id integer primary key autoincrement, name text, age integer);
```

そして id = 0, id = 1 の要素を順番に挿入していく。

```terminal:ターミナル
insert into users(name, age) values('Yoshizaki', 27);
insert into users(name, age) values('Kikagaku', 2);
```

select コマンドで DB を確認する。

```terminal:ターミナル
select * from users;
```

その結果

```terminal:ターミナル
1|Yoshizaki|27
2|Kikagaku|2
```

と出力されれば、正しく DB は作られている。対話モードからは ``.exit`` で抜けられる。

## データベースモデルの定義

データベース(DB)の中身をどのような object で定義するかを以下の model.py で決める。これも SQLAlchemy ライブラリで可能である。

```python:model.py
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class User(Base):
    __tablename__='users'
    
    id = Column(Integer, primary_key = True)
    name = Column(String)
    age = Column(Integer)
```
SQLite の primary key に id を採用したため、モデルでも同様に指定している。

## ブラウザへの表示

index2.html は以下のとおり。（後で編集する。）

```html:index2.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content = "width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
</head>
<body>
	<hl>Flask チュートリアル</hl>
	{% for user in users %}
		<p>名前: {{user.name}}</p>
	{% endfor %}
</body>
</html>
```
Part1 と同様に http://127.0.0.1:5000/index2 にアクセスして以下が表示されていれば成功である。

```
Flask チュートリアル
名前: Yoshizaki

名前: Kikagaku
```

## Bootstrap を用いて編集
CSS （cascading style sheets） のフレームワークである Bootstrap を使って index2.html を以下のように書き換える。
Bootstrap はよく使用されるスタイルが予め定義されており便利である。コードは[こちら](https://getbootstrap.com/docs/4.0/getting-started/introduction/)から引用した。

```html:index2.html
d<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content = "width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
	<!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>
<body>
	<div class="container">
		<div class="row">
			<hl>Flask チュートリアル</hl>
			<table class="table table-striped table-hover">
				<thread>
					<tr>
						<th scope="col">#</th>
						<th scope="col">Name</th>
						<th scope="col">Age</th>
					</tr>
				</thread>
				<tbody>
					{% for user in users %}
						<tr>
							<td>{{user.id}}</td>
							<td>{{user.name}}</td>
							<td>{{user.age}}</td>
						</tr>
					{% endfor %}
				</tbody>
			</table>
		</div>
	</div>
</body>
</html>
```

同様に、http://127.0.0.1:5000/index2 にアクセスして以下が表示されていれば成功である。

![Sg0U7US.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612858/6deb3e3e-1d58-86e2-f573-b4c9d0af9fd0.png)

## 参考
[データ収集からWebアプリ開発まで実践で学ぶ機械学習活用ガイド](https://book.mynavi.jp/supportsite/detail/9784839969226.html) の chapter 3-4-1 および chapter 3-5