はじめに
この記事はPython Beginners沖縄というコミュニティの初心者向けPython勉強会のために作った資料ですが、せっかく作った資料をpcに眠らせるのはもったいないと思ったため一部修正・加筆したものを公開します。
ある程度初心者向けの内容を想定して、出来る限り専門用語を省きざっくりとした説明を書いていますが、もしわかりにくい箇所・もう少し別の言い方したほうがいいかもしれないどあればアドバイスいただけると助かります。
参考文献
大変参考にさせていだたきました。ありがとうございます。
PythonのFlaskでデータベースを利用する方法(Flask-SQLAlchemy)
https://note.com/junyaaa/n/n9eab953c73c9#zdJy9
Python+Flask環境をDockerで構築する
https://qiita.com/kai_kou/items/e78b546b9820c7d8f1f9
そもそもPythonとは?
プログラミング言語の1つ。文法がシンプルで機械学習やデータ分析・webアプリ開発など幅広い分野で使える。
Flaskとは?
Python用の軽量なWebアプリケーションフレームワーク。
Djangoなどの他のフレームワークと比べて、学習コストが低いというメリットもある。
ちなみに、フレームワークとは開発のための枠組みを作ってくれるもの。
flask_sqlalchemyとは?
Flaskからデータベースを利用する際に、SQL文を書かずにPythonコード上からデータベースを操作できるようになるライブラリ。
データベースとは?
データを1つの場所に集めて、必要な時に必要なデータを集められるようにしたもの。
例えば、SNSでは、アカウント情報(メアド、パスワード、ユーザ名など)や投稿した内容などをデータベースに記録して管理している。
SQLとは?
データベースを操作するための言語。データベースにデータを挿入したり、検索するといったことが可能。
準備
pythonのインストール
環境構築の参考になるサイト
Flaskのインストール
$ pip install flask
flask_sqlalchemyのインストール
$ pip install flask_sqlalchemy
環境構築めんどくさいかつ初心者ではない方向け(Docker)
Flaskの環境構築をDockerで構築できるようにサンプルと同梱してあるので、ローカルで環境構築したくない方、環境構築めんどくさい方などはそちらをお使いください。
今回作るもの
こんな感じの某掲示板に若干寄せた感じの掲示板。
名前とメッセージを打って送信するだけのとてもシンプルな掲示板。
完成形のリポジトリ
フォルダ構成
この通りにファイルを作成・配置する。画像は写真ACというサイトからお借りしたものを使う。
app/
├ static/
│ └ css/
│ └ style.css
│ └ images/
│ └ backgroud.jpg
├ templates/
│ └ index.html
└ app.py
完成したコード
だらだら説明しても、ねむくなるので完成形(`・ω・´)
from flask_sqlalchemy import SQLAlchemy
from flask import Flask, render_template, request, redirect, url_for
import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.chat'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Chat(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_name = db.Column(db.String(16), nullable=False)
message = db.Column(db.String(128), nullable=False)
timestamp = db.Column(db.String(28), nullable=False)
@app.route('/')
def index():
data = Chat.query.all()
return render_template('index.html',data=data)
#以下追加↓
@app.route('/add', methods=['POST'])
def add():
user_name = request.form['user_name']
message = request.form['message']
dt_now = datetime.datetime.now()
timestamp = dt_now.strftime('%Y/%m/%d %H:%M:%S')
if not(user_name):
user_name = "名無しの人"
new_message = Chat(message=message,user_name=user_name,timestamp=timestamp)
db.session.add(new_message)
db.session.commit()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
<!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>Chat.html</title>
<link rel="stylesheet" href="{{ url_for('static',filename='css/style.css') }}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Hachi+Maru+Pop&display=swap" rel="stylesheet">
</head>
<body>
<h1>29ちゃっと</h1>
<form action="/add" method="POST" class="form">
<input type="text" name="user_name" placeholder="名無しさん"/>
<br>
<input type="text" name="message" placeholder="input chat!!"/>
<input type="submit" value="送信"/>
</form>
<!--以下追加-->
<div class="contents">
<br>
{% for d in data %}
<p>{{d.id}}. 名前: <span class="name">{{d.user_name}}</span> {{d.timestamp}}</p>
<p> {{d.message}}</p>
{% endfor %}
<!---------->
</div>
</body>
</html>
body {
background-image: url("/static/images/background.jpg");
background-repeat: repeat-y;
}
h1 {
font-family: 'Hachi Maru Pop', cursive;
font-size: 40px;
margin: 20px auto;
}
.form {
/*background-color: blueviolet;*/
}
.form input {
height: 25px;
border-radius: 4px;
margin: 2px auto;
}
.form input:nth-child(1) {
width: 200px;
}
.form input:nth-child(3) {
width: 600px;
}
.form input:nth-child(4) {
height: 32px;
width: 80px;
}
.contents {
background-color: rgb(255, 255, 255);
border-radius: 10px;
margin: 20px 15px;
border: 1px solid #3c3c3c;
padding: 10px 5px;
box-shadow: 2px 2px 6px rgb(157, 157, 157);
}
.contents .name {
color: rgb(31, 91, 181);
}
app = Flask(__name__)
でFlaskのインスタンスを作成。
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.chat'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
こちらの行でデータベースの設定をしている。今回は、簡単にサクッと実装したいのでsqliteを使用する。
ちなみに、app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
はリソースの節約のための設定なので、特に気にしなくていい。
テーブルのクラスを定義
class Chat(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_name = db.Column(db.String(16), nullable=False)
message = db.Column(db.String(128), nullable=False)
timestamp = db.Column(db.String(28), nullable=False)
データベースにどういう値を記録・管理するのかをここに定義する。
今回は以下のようにテーブルを定義する。
- id
- 重複した値を区別するためのキー(プライマリーキー)。
- user_name
- 投稿者名。
- message
- 投稿内容。
- timestamp
- 投稿時間。
例
id | user_name | message | timestamp |
---|---|---|---|
1 | 村人1 | 初めての投稿 | 2021/08/10 20:28:59 |
2 | 村人2 | 2番目 | 2021/08/11 10:28:59 |
3 | 村人3 | 3番目 | 2021/08/11 21:28:59 |
ちなみに、db.chatというデータベースがまだないので作成する。
今回は、リポジトリにinit_db.pyというファイルを用意しているのでそれを実行すれば作成できる。
ルーティングを作成
@app.route('/')
def index():
data = Chat.query.all()
return render_template('index.html',data=data)
/
にアクセスすると、index.htmlを返す、つまり表示させるようにしている。
このとき、データベースのChatモデルのデータをdata = Chat.query.all()
で全て取得し、それをindex.htmlに渡すようにしている。
今回は、/
で投稿と表示を行い、/add
でデータベースに追加する処理を書く。
<input type="text" name="user_name" placeholder="名無しさん"/>
このように、nameを指定してたinputタグからPOSTされた値を
user_name = request.form['user_name']
このように書いて受け取ることができる。
また、それらの値を以下のように書いてデータベースに渡す。
new_message = Chat(message=message,user_name=user_name,timestamp=timestamp)
db.session.add(new_message)
db.session.commit()
そして、値を渡した後、index.htmlにリダイレクトするようにしている。
return redirect(url_for('index'))
データを表示する
先程の処理でidnex.htmlにdataが渡されたので今度はそれを表示したい。
{% for d in data %}
<p>{{d.id}}. 名前: <span class="name">{{d.user_name}}</span>
{{d.timestamp}}</p>
<p> {{d.message}}</p>
{% endfor %}
html内でpythonコードを書きたい場合、{{}}に変数名を入れることで中身を表示できる。
また、for文(繰り返し処理)を書く際は、{% for d in data %}のように書き始めて、{% endfor %}でfor文を閉じる。
今回やっていることを軽く説明すると、dataで渡された値をfor文でループさせてd.id, d.user_nameのように一つずつ値を取り出して表示している。
動作確認
以下のコマンドをターミナル(コマンドプロンプト)から入力しよう。
$ cd app
$ python app.py
localhost:5000にアクセスしてみて、次の画面が表示されたら完成!!
画面が表示されたら、適当にメッセージを送信してきちんと表示されるか確認してみよう。