まえがき
PythonでFlask-SQLAlchemyを使っているときにエラーが発生して、解決に少し時間がかかったので備忘として記載します。
(解決してみれば非常に初歩的な事象でしたが...)
やろうとしたこと
Flask-SQLAlchemyでDB、テーブルを作成し、CSVから取り込んだ値を初期値として追加しようとしていました。
データは以下のような形です。
name(文字列) | level(int) | difficulty(float、空の場合がある) |
---|---|---|
ほげ | 1 | 0.5 |
ふが | 2 | 空 |
... |
Modelは以下です。
class Hoge(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text)
level = db.Column(db.Integer)
difficulty = db.Column(db.Float)
追加する部分のコードは以下です。
datalist = []
with open('data.csv', mode='r', encoding='utf-8') as f:
tmp = csv.reader(f, delimiter=",", doublequote=True, lineterminator="\r\n", skipinitialspace=True)
for i in tmp:
datalist.append(i)
for i in datalist:
h = Hoge(
name = i[0],
level = i[1],
difficulty = i[2]
)
db.session.add(h)
エラー内容
sqlalchemy.exc.StatementError:
(raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely)
(builtins.ValueError) could not convert string to float:
[SQL: INSERT INTO hoge (name, level, difficulty) VALUES (?, ?, ?)]
[parameters: [{'difficulty': '', 'name': 'ふが', 'level': '2'}]]
最初「sqlalchemy.exc.StatementError:(...)」の部分だけ見てしまい、これで検索して色々迷走していました...
本当に見るべきなのは以下でした。
(builtins.ValueError) could not convert string to float:
[SQL: INSERT INTO hoge (name, level, difficulty) VALUES (?, ?, ?)]
[parameters: [{'difficulty': '', 'name': 'ふが', 'level': '2'}]]
原因
could not convert string to float
はFlask-SQLAlchemy固有のエラーではなく、pythonのエラーです。
(builtinsと書いてありますね。私は見逃してました...)
このエラー事態は文字列からfloatに変換できない場合に表示されるようです。
(「1,000.5」のようにコンマがあると変換できない等)
今回の場合は、空の文字列をfloatに変換できずエラーとなっていたようでした。
改善方法
値を設定する部分に三項演算子を用いて、空の文字列がある場合はNone
を入力するように変更しました。
datalist = []
with open('data.csv', mode='r', encoding='utf-8') as f:
tmp = csv.reader(f, delimiter=",", doublequote=True, lineterminator="\r\n", skipinitialspace=True)
for i in tmp:
datalist.append(i)
for i in datalist:
h = Hoge(
name = i[0],
level = i[1],
difficulty = i[2] if i[2] != '' else None # 変更
)
db.session.add(h)
これでエラー解消できました!
tmp = Hoge.query.all()
print(tmp)
print(tmp[0].__dict__)
[<Hoge 1>, <Hoge 2>]
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000001AE0EF1F4E0>, 'id': 1, 'name': 'ほげ', 'difficulty': 0.5, 'level': 1}
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000001AE0EE76EF0>, 'name': 'ふが', 'level': '2', 'difficulty': None, 'id': 2}
補足
環境
OS:Windows10
pythonバージョン:3.7.3
Flaskバージョン:1.0.3
Flask-SQLAlchemyバージョン:2.5.1
本事象が再現できるコード
コード一覧を載せておきます。
Flask, Flask-SQLAlchemyの導入の仕方は各自調べてください。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Hoge(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text)
level = db.Column(db.Integer)
difficulty = db.Column(db.Float)
db.create_all()
datalist = [['ほげ', '1', '0.5'], ['ふが', '2', '']]
for i in datalist:
h = Hoge(
name = i[0],
level = i[1],
difficulty = i[2]# if i[2] != '' else None # ここの三項演算子を有効にするとエラー解消します
)
db.session.add(h)
tmp = Hoge.query.all()
print(tmp)
print(tmp[0].__dict__)
print(tmp[1].__dict__)
参考元
三項演算子:https://qiita.com/howmuch515/items/bf6d21f603d9736fb4a5
could not convert string to float
エラー:https://engineeeer.com/python-convert-string-to-float/