Flaskで簡易ブログアプリの作成！データベース操作も~Flask超入門 vol.2~をやってみる

# はじめに
いまにゅのプログラミング塾さんの
Flaskで簡易ブログアプリの作成！データベース操作も~Flask超入門 vol.2~
https://www.youtube.com/watch?v=mW0_60SRr3s
で作られているアプリを作っていきます。

 ・Windows11
 ・Python 3.13.2
 ・Flask 3.1.0

# アプリケーションのセットアップ
環境整備
```bash:Git Bash
$ cd [プロジェクトを作りたいファイルのファイルパス]
$ mkdir [プロジェクト名]
$ cd [プロジェクト名]
$ git init
$ python -m venv [仮想環境名]
```
仮想環境の使い方
```bash:Git Bash
# 起動
$ source ./venv/Scripts/activate
# 終了
$ deactivate
```
Flaskのインストール
```bash:Git Bash
$ pip install Flask
```
ファイルの作成
```bash:Git Bash
$ touch app.py
$ mkdir templates
$ cd templates
$ touch index.html
$ cd ..
```
環境変数の設定
```bash:Git Bash
#設定
$ export FLASK_APP=app
$ export FLASK_ENV=development
# 確認
$ echo $FLASK_APP
$ echo $FLASK_ENV
```

# ソースコード
```python:app.py
from flask import Flask
from flask import render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, LoginManager
from datetime import datetime
import pytz
import os

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SECRET_KEY'] = os.urandom(24)
db = SQLAlchemy(app)

login_manager = LoginManager()
login_manager.init_app(app)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50), nullable=False)
    body = db.Column(db.String(300), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False,
                        default=datetime.now(pytz.timezone('Asia/Tokyo')))

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(30), nullable=False, unique=True)
    password = db.Column(db.String(12))
```
テーブル定義
```bash:GitBash
$ python
# blog.db
>>> from app import app, db
>>> with app.app_context():
...　　db.create_all()
```
instanceフォルダにblog.dbが生成される

# 完成版
```python:app.py
from flask import Flask
from flask import render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import pytz

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
db = SQLAlchemy(app)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50), nullable=False)
    body = db.Column(db.String(300), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False,
                        default=datetime.now(pytz.timezone('Asia/Tokyo')))

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        posts =Post.query.all()
        return render_template('index.html', posts=posts)

@app.route('/create', methods=['GET', 'POST'])
def create():
    if request.method == 'POST':
        title= request.form.get('title')
        body= request.form.get('body')

        post = Post(title=title, body=body)

        db.session.add(post)
        db.session.commit()
        return redirect('/')

    else:
        return render_template('create.html')

@app.route('/<int:id>/update', methods=['GET', 'POST'])
def update(id):
    post = Post.query.get(id)
    if request.method == 'GET':
        return render_template('update.html', post=post)
    else:
        post.title= request.form.get('title')
        post.body= request.form.get('body')

        db.session.commit()
        return redirect('/')

@app.route('/<int:id>/delete', methods=['GET'])
def delete(id):
    post = Post.query.get(id)

    db.session.delete(post)
    db.session.commit()
    return redirect('/')
```

```html:base.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>Document</title>
</head>
<body>
    {% block content %}
    {% endblock %}
</body>
</html>
```

```html:index.html
{% extends "base.html" %}
{% block content %}
    <h1>ブログアプリケーション</h1>
    <a href="/create" role="button">新規作成画面</a>
    {% for post in posts %}
    <article>
        <h2>{{ post.title }}</h2>
        <a href="/{{ post.id }}/update" role="button">編集</a>
        <a href="/{{ post.id }}/delete" role="button">削除</a>
        <p>作成日時: {{ post.created_at }}</p>
        <p>{{ post.body }}</p>
    </article>
    {% endfor%}
{% endblock %}
```

```html:create.html
{% extends "base.html" %}
{% block content %}
<h1>新規登録</h1>
<form method="POST">
    <label for="title">タイトル</label>
    <input type="text" name="title">
    <label for="body">内容</label>
    <input type="text" name="body">
    <input type="submit" value="新規登録">
</form>
{% endblock %}
```

```html:update.html
{% extends "base.html" %}
{% block content %}
<h1>編集画面</h1>
<form method="POST">
    <label for="title">タイトル</label>
    <input type="text" name="title" value={{ post.title }}>
    <label for="body">内容</label>
    <input type="text" name="body" value={{ post.body }}>
    <input type="submit" value="更新">
</form>
{% endblock %}
```

# 総括
動画ではflask_sqlalchemyというアプリを使ってDBを操作していたのでSQLでDB操作をやりたいと思いました。
flaskを学びたくてやったのですがflaskと親和性が高いライブラリの勉強の必要性を強く感じました。
ほぼ一日でやったのでコメントをろくに書かないまま終わったので今後は簡単なものでもしっかりコメントを残していきたいと思いました。