flask sqlalchemyで躓いたこと。
実行環境
Raspberry Pi Zero W Rev 1.1
Raspberry Pi OS Lite (32bit)(Debian version: 11 (bullseye))
ufw 0.36
nginx 1.18.0
python 3.9.2
-Flask 2.3.2
-Flask-SQLAlchemy 3.0.3
-Jinja2 3.1.2
-pyserial 3.5
-SQLAlchemy 2.0.13
前提条件
raspiやufw, nginxなどの初期設定が済んでいる。(リバースプロキシ設定など…)
本文
flaskの勉強のために以下のようなコードを作成した
import serial
import sqlite3
from flask import Flask, request, render_template
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
ser = serial.Serial(
port='/dev/ttyAMA0', # Raspberry Pi Zero のシリアルポート名
baudrate=115200, # ボーレート
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
app = Flask(__name__)
# データベース作成
db_uri = 'sqlite:///test.db'
app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
class Comment(db.Model):
__tablename__ = 'comment'
id_ = db.Column(db.Integer, primary_key=True, autoincrement=True)
pub_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
name = db.Column(db.Text())
comment = db.Column(db.Text())
db.create_all()
# ホーム画面
@app.route("/")
def index():
return render_template("index.html")
# 設定画面
@app.route("/settings")
def settings():
return render_template("settings.html")
# index.htmlに投稿データを渡す
@app.route("/data", methods=['GET'])
def data():
# テーブルから投稿データをSELECT文で引っ張ってくる
text = Comment.query.all()
return render_template("data.html", lines=text)
# 投稿の送信とデータベース追加
@app.route("/result", methods=["POST"])
def result():
# 現在時刻 投稿者名 投稿内容を取得
date = datetime.now()
comment = request.form["comment_data"]
name = request.form["name"]
# テーブルに格納するデータを定義する
comment_data = Comment(pub_date=date, name=name, comment=comment)
# テーブルにINSERTする
db.session.add(comment_data)
# テーブルへの変更内容を保存
db.session.commit()
return render_template("result.html", comment=comment, name=name, now=date)
# マニュアル画面
@app.route("/manual")
def manual():
return render_template("manual.html")
# シリアル通信の送信
@app.route("/send_serial/<int:medicine_number>")
def send_serial(medicine_number):
if medicine_number in [1, 2, 3]:
# シリアル通信の送信
ser.write(str(medicine_number).encode())
print(f"Send serial data: {medicine_number}")
return 'OK'
else:
return 'ERROR'
if __name__ == "__main__":
app.run("0.0.0.0", debug="True")
flaskやsqlalchemyなどの仕様確認のために組んだコードである。
いろいろなサイトで紹介されているコードは上記のように”db.create_all()”がclassの直後に書かれているが、バージョンが違うためなのかこの記述だと実行できてもOperatingErrorが出るか、実行エラーになる。
書き換えたコード
import serial
import sqlite3
from flask import Flask, request, render_template
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
ser = serial.Serial(
port='/dev/ttyAMA0', # Raspberry Pi Zero のシリアルポート名
baudrate=115200, # ボーレート
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
app = Flask(__name__)
# データベース作成
db_uri = 'sqlite:///test.db'
app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
class Comment(db.Model):
__tablename__ = 'comment'
id_ = db.Column(db.Integer, primary_key=True, autoincrement=True)
pub_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
name = db.Column(db.Text())
comment = db.Column(db.Text())
with app.app_context():
db.create_all()
# ホーム画面
@app.route("/")
def index():
return render_template("index.html")
# 設定画面
@app.route("/settings")
def settings():
return render_template("settings.html")
# index.htmlに投稿データを渡す
@app.route("/data", methods=['GET'])
def data():
# テーブルから投稿データをSELECT文で引っ張ってくる
text = Comment.query.all()
return render_template("data.html", lines=text)
# 投稿の送信とデータベース追加
@app.route("/result", methods=["POST"])
def result():
# 現在時刻 投稿者名 投稿内容を取得
date = datetime.now()
comment = request.form["comment_data"]
name = request.form["name"]
# テーブルに格納するデータを定義する
comment_data = Comment(pub_date=date, name=name, comment=comment)
# テーブルにINSERTする
db.session.add(comment_data)
# テーブルへの変更内容を保存
db.session.commit()
return render_template("result.html", comment=comment, name=name, now=date)
# マニュアル画面
@app.route("/manual")
def manual():
return render_template("manual.html")
# シリアル通信の送信
@app.route("/send_serial/<int:medicine_number>")
def send_serial(medicine_number):
if medicine_number in [1, 2, 3]:
# シリアル通信の送信
ser.write(str(medicine_number).encode())
print(f"Send serial data: {medicine_number}")
return 'OK'
else:
return 'ERROR'
if __name__ == "__main__":
app.run("0.0.0.0", debug="True")
上記のようにdb.create_all()をそのまま書くのではなくwith app.app_context():下に書いてあげると正常に動作する。
# db.create_all()
with app.app_context():
db.create_all()
app.app_context()を使用することで、アプリケーション固有の機能にアクセスできるコンテキストが作成されます。
これにより、db.create_all()などのデータベース関連の操作をアプリケーションコンテキスト内で使用できるようになります。
この記事が気に入ったらサポートをしてみませんか?