1. はじめに
今回は、SQLiteを使い投稿したデーターをDBに保存するところまで行いたいと思います。
2. 全体の流れ
1.事前準備(SQLite3のインストール)
2.共通化
3.投稿内容のDB登録(今回のメイン)
4.DB登録処理(今回のメイン)
1. 事前準備 SQLite3のインストール
-
「Precompiled Binaries for Windows」まで移動し、
「sqlite-tools-win32-x86-3360000.zip」をダウンロード
-
ダウンロードしたら、任意の場所でZIPファイルを解凍。
-
解凍すると、sqldiff.exe、sqlite3.exe、sqlite3_analyzer.exeのファイルが存在する。
-
3つのファイルを設置するためのフォルダを作成する。私の場合は、以下にsqliteという
フォルダを作成する。
C:\PC-Work\dockerenv\sqlite
-
sqliteフォルダー内に、sqldiff.exe、sqlite3.exe、sqlite3_analyzer.exeをコピーします。
-
コマンドから実行出来るように、Pathを通す。
-
Pahtが通ったか、以下のコマンドを実行。
$env:path.split(";")
sqlitへPATHが通ったことを確認
C:\PC-Work\dockerenv\sqlite
- sqlalchemyのインストール(仮想環境内で実行すること)
pip install flask-sqlalchemy
- slqalchmeyがインストールされたことを確認
pip list
Package Version
---------------- -------
click 8.1.3
colorama 0.4.6
Flask 2.2.2
Flask-SQLAlchemy 3.0.2
greenlet 2.0.1
itsdangerous 2.1.2
Jinja2 3.1.2
MarkupSafe 2.1.1
pip 22.3
setuptools 65.5.0
SQLAlchemy 1.4.45
Werkzeug 2.2.2
前回の続きから
ディレクトリ構造
pydir/
┣myproject/ ->このディレクトリで仮想環境有効化のコマンドを実行&flask runコマンドもここで
┣venv/
┣instance/
┣blog.db ->今回作成
┣hello.py
┣app.py -> 今回作成
┣templates/
┣hello.html
┣index.html ->今回作成
┣base.html ->今回作成
┣create.html ->今回作成
仮想環境の有効化
.venv\Scripts\activate.ps1
app.pyファイル作成
New-Item app.py
app.py記述
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def hello():
return render_template('index.html')
templatesフォルダに移動して、index.htmlファイルを作成
New-Item index.html
index.html記述
<!DOCTYPE html>
<html lang="en">
<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>
<h1>ブログアプリケーション</h1>
<article>
<h2>記事1</h2>
<p>作成日時: 2022/12/17 10:00</p>
<p>記事1の内容</p>
</article>
<article>
<h2>記事2</h2>
<p>作成日時: 2022/12/17 11:00</p>
<p>記事2の内容</p>
</article>
</body>
</html>
環境変数設定
$env:FLASK_APP = "app"
デバッグモード
$env:FLASK_ENV = "development"
Flaskの起動
flask run
'FLASK_ENV' is deprecated and will not be used in Flask 2.3. Use 'FLASK_DEBUG' instead.'FLASK_ENV' is deprecated and will not be used in Flask 2.3. Use 'FLASK_DEBUG' instead.'FLASK_ENV' is deprecated and will not be used in Flask 2.3. Use 'FLASK_DEBUG' instead. * Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a
production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
* Restarting with stat
'FLASK_ENV' is deprecated and will not be used in Flask 2.3. Use 'FLASK_DEBUG' instead.'FLASK_ENV' is deprecated and will not be used in Flask 2.3. Use 'FLASK_DEBUG' instead.'FLASK_ENV' is deprecated and will not be used in Flask 2.3. Use 'FLASK_DEBUG' instead. * Debugger is active!
* Debugger PIN: 261-206-630
ブラウザでhttp://127.0.0.1:5000/
へアクセス
ここまでが事前準備。
エラーが出た場合は、前回までのコードの見直しが必要。
2. 共通化
templatesフォルダ内に、HTMLで共通で利用するためのファイル(base.html)を作成する。
{% block content %} {% endblock %} の間に、index.html内の {% block content %} から
{% endblock %} の内容が埋め込まれる。
base.html記載
<!DOCTYPE html>
<html lang="en">
<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>
<!-- ここに、index.htmlの共通化要素(記事1とか記事2などの内容)が埋め込まれる -->
{% block content %}
{% endblock %}
</body>
</html>
index.htmlが、base.htmlを読み込むための編集
{% extends "base.html" %} で、base.htmlの
{% extends "base.html" %} <!--追記 -->
{% block content %} <!--追記 -->
<h1>ブログアプリケーション</h1>
<article>
<h2>記事1</h2>
<p>作成日時: 2022/12/17 10:00</p>
<p>記事1の内容</p>
</article>
<article>
<h2>記事2</h2>
<p>作成日時: 2022/12/17 11:00</p>
<p>記事2の内容</p>
</article>
{% endblock %} <!--追記 -->
ブラウザで、127.0.0.1:5000
にアクセスすると、前回と変わらない画面が表示されれば、共通化成功です。
3. 投稿内容のDB登録
投稿は、HTTPのPOSTというメソッドを使い、DBに投稿(送信)される。
from flask import Flask
from flask import render_template
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import pytz
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///blog.db" # 今回作成するDB名
db = SQLAlchemy(app)
# 以下の部分がClassを使ってDBへPOSTするデーターを定義している。
# db.String()は、入力可能な文字数を定義
# nullable=Falseは、nullでPOSTはできないように定義
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("/")
def hello():
return render_template('index.html')
DB作成(SQLiteを使用)
仮想環境内で以下のコマンドを実行すること。
対話モードで実施(app.pyがあるところで)
python
Python 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> from app import app, db
>>> with app.app_context():
... db.create_all()
...
>>> exit()
上記コマンドは分かりにくいのでキャプチャーも載せておきます。
新規登録画面を作成するため、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 %}
index.htmlでは、「新規作成画面」へ遷移するためのボタンを作成する。
<a href="/create" role="button">新規作成画面</a>
を追加。
{% extends "base.html" %}
{% block content %}
<h1>ブログアプリケーション</h1>
<!-- ボタン作成 -->
<a href="/create" role="button">新規作成画面</a>
<article>
<h2>記事1</h2>
<p>作成日時: 2022/12/17 10:00</p>
<p>記事1の内容</p>
</article>
<article>
<h2>記事2</h2>
<p>作成日時: 2022/12/17 11:00</p>
<p>記事2の内容</p>
</article>
{% endblock %}
from flask import Flask
from flask import render_template
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を使ってDBへPOSTするデーターを定義している。
# db.String()は、入力可能な文字数を定義
# nullable=Falseは、nullでPOSTはできないように定義
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("/")
def hello():
return render_template('index.html')
# 新規登録画面へ遷移するためのルーティング追加
@app.route("/create")
def create():
return render_template('create.html')
base.htmlは、修正なし。
<!DOCTYPE html>
<html lang="en">
<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>
<!-- ここに、HTMLの共通化が埋め込まれる -->
{% block content %}
{% endblock %}
</body>
</html>
127.0.0.1:5000
にアクセス
ブログのTop画面に「新規作成画面」ボタンが表示される。「新規作成画面」をクリック。
新規作成画面でタイトルと内容を入力し、新規登録ボタンをクリック
app.py側でPOSTを受け付ける仕組みを作っておかなければならない。上記では、POSTで送信しているが、HTTPはデフォルトでGET送信するため。
app.py側で、GETとPOSTの両方を受け付ける様に変更を行う。
from flask import Flask
from flask import render_template
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("/")
def hello():
return render_template('index.html')
@app.route("/create", methods=['GET', 'POST']) # ここを追加
def create():
return render_template('create.html')
再度、「新規作成画面」から新規登録を行う。
以下の画面が表示されれば成功です。無事、POST(登録内容がDBへ送信)される。
ただし、DBには、送信したデーターは登録されていない。
4. DB登録処理
以下からDB登録処理
処理内容としては、POST後に、**db.session.commit()**でDBへコミットし、return redirect('/')で
トップページにリダイレクトを行う。
上記をif文内に記載している。
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("/")
def hello():
return render_template('index.html')
@app.route("/create", methods=['GET', 'POST']) # ここを追加
def create():
# requestがPOSTだったら
if request.method == 'POST':
# request.form.get()でフォームで入力した情報を取得(事前に、requestのimport必要)
title = request.form.get('title')
body = request.form.get('body')
post = Post(title=title, body=body)
# DBにpostされてきたデーターを追加(add)する
db.session.add(post)
# 変更を保存
db.session.commit()
# DB登録後、トップページにリダイレクト
return redirect('/')
# POSTではない場合、つまり、GETでアクセスした場合の処理
else:
return render_template('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 %}
{% extends "base.html" %}
{% block content %}
<h1>ブログアプリケーション</h1>
<!-- ボタン作成 -->
<a href="/create" role="button">新規作成画面</a>
<article>
<h2>記事1</h2>
<p>作成日時: 2022/12/17 10:00</p>
<p>記事1の内容</p>
</article>
<article>
<h2>記事2</h2>
<p>作成日時: 2022/12/17 11:00</p>
<p>記事2の内容</p>
</article>
{% endblock %}
新規登録画面に遷移するので、「タイトル」「内容」を入力し、新規登録ボタンをクリックするとDBへ登録が行われ
最初の画面に戻る。エラーがでなければOK。
登録した内容が表示されない理由は、まだ、登録したデーターを取得して、表示する処理を追加していないため。
DB登録の状況確認については、次回。