3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SQLModelを試してみた

Last updated at Posted at 2021-11-03

#SQLModelとは
公式はこちら

現在PythonのWebFrameworkで最も注目されている(?)FastAPIの作者tiangolo氏による新しいPythonのORMである。
###特徴
Pythonの型付けを強力にサポートするPydanticと、有名なORMのSQLAlchemyをベースにラップしたもので、直感的で短いコードが書けてSQLAlchemyとの互換性も優れているようで、平たく言うと今までデータベースのスキーマをPydanticで定義していたが、SQLAlchemyとFastAPIを使う場合は不要になったということ(だろう)。

早速試してみました。


環境 Ubuntu20.04 Pipenv Python3.8.10 MySQL8.0 VScode

###インストール

pipenv install fastapi sqlmodel uvicorn

とやるも...

Creating a Pipfile for this project...
Installing fastapi...
Adding fastapi to Pipfile's [packages]...
✔ Installation Succeeded 
Installing sqlmodel...
Adding sqlmodel to Pipfile's [packages]...
✔ Installation Succeeded 
Installing uvicorn...
Adding uvicorn to Pipfile's [packages]...
✔ Installation Succeeded 
Pipfile.lock not found, creating...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✘ Locking Failed! 

ぐぬぬ。。。依存関係の問題でLockfileを作れていない。。。

Hint: try $ pipenv lock --pre if it is a pre-release dependency.

と、あるので

/dev/python_code$  pipenv lock --pre
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success! 
Updated Pipfile.lock (d6534a)!

できた!

##FastAPIによりサーバを起動。

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

からのコマンド

app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [3921] using statreload
INFO:     Started server process [3923]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

サーバ起動を確認。(実はuvicornのエラーが出たが、pipenv shell で解決)

##DBに接続する

MySQLを用意するところは割愛します。私はAWSのEC2・linuxインスタンスにMySQLを立てています。接続情報が一部異なるだけで、ローカルで立てても公式通りにsqliteを使用しても問題ないです。

ここからは公式に沿ってSQLModelを使用してみます。
以下のカラムを定義します。

・id(int)
・name(str)
・nick_name(str)
・age(int)

データを以下のように格納したいとします。

id name nick_name age
1 朝倉未来 路上の伝説 29
2 朝倉海 海ぴょん 28
3 齋藤光 シバター 36

まずはスキーマを定義します。

from typing import Optional
from sqlmodel import Field, SQLModel

class fighters(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

Python3.6より導入された型ヒントが用いられています。

fightersクラスはSQLModelを継承しており、PydanticのValidationが機能し、[id]と[age]にはオプションでint型を、nameとsecret_nameには強制的にstr型が入ります。

##DBにデータを格納する

上記で書いたテーブルとデータをDBへ格納します。

from typing import Optional
from sqlmodel import Field, SQLModel, create_engine, Session


class fighters(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

#1.fightersのインスタンスを作成します。
fighter_1 = fighters(name="朝倉未来", secret_name="路上の伝説", age=29)
fighter_2 = fighters(name="朝倉海", secret_name="海ぴょん")
fighter_3 = fighters(name="斎藤光", secret_name="シバター", age=35)

#2.DB接続情報を作る。localhostやIPが入ります。3306は今回使用したMySQLのポートです。
url = f'mysql+://{"user名"}:{"DBのpassword"}@{"ソース"}/{"テーブル名"}'
engine = create_engine(url, echo=True)

#3.データベースを作成、セッションをはりデータをコミットします。
SQLModel.metadata.create_all(engine)

with Session(engine) as session:
    session.add(fighter_1)
    session.add(fighter_2)
    session.add(fighter_3)
    session.commit()

以下のコマンドを入力

python3 main.py

がしかし

No module named 'MySQLdb'

sqlalchemy内部でMySQLdbというモジュールをインポートしているがそれが見当たらないとのこと。

pymysqlのインストールとソースの書き換えをする。
pipenv install pymysql

//{"user名"}:{"DBのpassword"}@{"ソース"}/{"テーブル名"}'

で、再度

python3 main.py
2021-11-04 00:31:26,438 INFO sqlalchemy.engine.Engine INSERT INTO fighters (name, secret_name, age) VALUES (%(name)s, %(secret_name)s, %(age)s)
2021-11-04 00:31:26,438 INFO sqlalchemy.engine.Engine [generated in 0.00077s] {'name': '朝倉未来', 'secret_name': '路上の伝説', 'age': 29}
2021-11-04 00:31:26,458 INFO sqlalchemy.engine.Engine INSERT INTO fighters (name, secret_name, age) VALUES (%(name)s, %(secret_name)s, %(age)s)
2021-11-04 00:31:26,458 INFO sqlalchemy.engine.Engine [cached since 0.02074s ago] {'name': '朝倉海', 'secret_name': '海ぴょん', 'age': None}
2021-11-04 00:31:26,493 INFO sqlalchemy.engine.Engine INSERT INTO fighters (name, secret_name, age) VALUES (%(name)s, %(secret_name)s, %(age)s)
2021-11-04 00:31:26,493 INFO sqlalchemy.engine.Engine [cached since 0.05552s ago] {'name': '斎藤光', 'secret_name': 'シバター', 'age': 35}
2021-11-04 00:31:26,523 INFO sqlalchemy.engine.Engine COMMIT

通った。

MySQLworkbenchで中を覗いてみます。
Screenshot from 2021-11-04 00-47-12.png

無事接続&テーブル作成できました。

###所感
・結局APIのスキーマを定義するときにPydantic使うのなら、それほどメリットはないかも。
・SQLModelはパッケージ管理にPoetry使ってるらしい。pipenvじゃなくてPoetryにしようかな。
・Mysqlとの接続方法はこれでよいのか?
今回FastAPI関係なかったな

次回はCRUDをやります。
間違いがあれば指摘していただけると助かります。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?