スクリプトのお勉強

fastapi + SQLAlchemy で CRUDアプリケーションを作ってみる

投稿日:2020年11月15日 更新日:

概要

勉強用に、PythonでPostgresqlを制御しようと思います。の続きです。

前回でPostgreSQLと、データベース/テーブルまでは用意したので、今回はAPIを作成しようと思います。

実行環境

実行環境は以下の通りです。

  • ubuntu 20.04
  • python 3.8
  • postgresql: v13
  • pipenv 2020.06

使用ライブラリ

以下をインストールしています。

pipenv install sqlalchemy
pipenv install Fastapi==0.61.2
pipenv install psycopg2==2.8.6
pipenv install fastapi-sqlalchemy
pipenv install pydantic[dotenv]

対象ソース

GitHubにあります。

ソース説明

以下がソース内容です。

|-- Pipfile
|-- Pipfile.lock
|-- README.md
|-- app
|   |-- run.py   <--------- ここから起動開始
|   |-- settings
|   |   `-- settings.py <-- 設定ファイル(.env)を読む
|   |-- urls.py  <--------- 受信するURLを記述
|-- layer
|   |-- __init__.py
|   |-- infra
|   |   |-- __init__.py
|   |   `-- db <-------- DB関連の内容
|   |       |-- __init__.py
|   |       |-- action.py  <--- CRUD処理を記述
|   |       |-- db.py      <--- engine
|   |       |-- models.py  <--- ORM
|   |       `-- schemas.py <--- 受送信のスキーマ
|   `-- present
`-- migration    <----- マイグレーション(yoyo-migrations)
    |-- migrations
    |   `-- 0001_create_addr.py
    `-- yoyo.ini

データベース環境の指定方法

.envファイルに置くことにしました。
.envに以下のように記述すると、アクセスできるようにしてあります。

DATABASE_URI = 'postgresql://testuser:testuserp@localhost/testdb'

起動

以下で起動します。

$ pipenv run uvicorn app.run:app --reload --host 0.0.0.0 --port 18000

SQLAlchemyの使用方法

大まかにSQLAlchemyの使い方は2つあります。

  • SQLAlchemy Core(主にSQLを素で使用する)
  • SQLAlchemy ORM(modelを作成し、modelで制御する)

また、使用する際は、以下のような考慮点を自分で組み合わせて開発する必要があります。

  • engine(DB接続先)をどのように管理するか
  • ORMの場合、modelをどのように作成するか
  • sessionをどのように管理するか

今回は、ORMを使用する方針にしました。

そして実質上”fastapi-sqlalchemy”にお任せになってしまいました。
今回のプログラムでは、以下のように使用しています。

DB(engine): layer/infra/db/db.py内で作成(DATABASE_URIもここで指定)する。
model: SQLAlchemy ORMを、layer/infra/db/models.pyで定義する。
session: “fastapi-sqlalchemy”内(DBSessionMiddleware)で作成する。session取得は以下のように行う。

from fastapi_sqlalchemy import db

fastAPI + SQLAlchemyの実現方法はいろいろあると思いますが、現時点では、これが一番お手軽な方法だと思います。

動作確認

作成は以下のようになります。

$ curl -X POST -H "Content-Type: application/json" -d '{"name":"ttttt83iksks", "addr":"100", "ipaddr":"192.168.0.0/16"}' http://localhost:18000/addrs/create

作成したデータは以下のように取得できます。

$ curl http://localhost:18000/addrs/find/4 | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": {
    "update_time": "2020-11-15T14:29:15.784526+09:00",
    "create_time": "2020-11-15T14:29:15.784509+09:00",
    "addr": "100",
    "id": 4,
    "ipaddr": "192.168.0.0/16",
    "name": "ttttt83iksks"
  }
}

全体が以下です。

$ curl http://localhost:18000/addrs | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": [
    {
      "update_time": "2020-11-15T14:15:58.246082+09:00",
      "create_time": "2020-11-15T14:15:58.246061+09:00",
      "addr": "100",
      "id": 1,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    },
    {
      "update_time": "2020-11-15T14:23:10.404737+09:00",
      "create_time": "2020-11-15T14:23:10.404714+09:00",
      "addr": "100",
      "id": 2,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    },
    {
      "update_time": "2020-11-15T14:26:29.539578+09:00",
      "create_time": "2020-11-15T14:26:29.539551+09:00",
      "addr": "100",
      "id": 3,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    },
    {
      "update_time": "2020-11-15T14:29:15.784526+09:00",
      "create_time": "2020-11-15T14:29:15.784509+09:00",
      "addr": "100",
      "id": 4,
      "ipaddr": "192.168.0.0/16",
      "name": "ttttt83iksks"
    }
  ]
}

updateは以下の通りです。

$ curl -X POST -H "Content-Type: application/json" -d '{"id":4 , "name":"ttttt83iksks", "addr":"住んでいるところ", "ipaddr":"192.168.1.0/16"}' http://localhost:18000/addrs/update
{"StatusCode":200,"ErrorCode":"","Result":{}}
$ curl "http://localhost:18000/addrs/find/4" | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": {
    "update_time": "2020-11-15T16:21:48.230994+09:00",
    "create_time": "2020-11-15T14:29:15.784509+09:00",
    "addr": "住んでいるところ",
    "id": 4,
    "ipaddr": "192.168.1.0/16",
    "name": "ttttt83iksks"
  }
}

削除は以下の通りです。

$ curl -X POST -H "Content-Type: application/json" -d '{"id":4}' http://localhost:18000/addrs/delete
{"StatusCode":200,"ErrorCode":"","Result":"delete success"}
$ curl "http://localhost:18000/addrs/find/4" | jq .
{
  "StatusCode": 200,
  "ErrorCode": "",
  "Result": null
}

OpenAPI(/docs)

この時点で自動作成した/docsは以下の通りです。

終わりに

APIを作成するだけなら結構簡単に作れました。
次は(出来たら) Nuxt.jsか何かで、これらAPIを使用して入出力を行う画面を作成したいと思います。

参考

https://fastapi.tiangolo.com/ja/

https://qiita.com/t-iguchi/items/d01b24fed05db43fd0b8

-スクリプトのお勉強
-,

執筆者:

関連記事

Selenium + Python によるアップロードアプリの動作確認プログラム作成

私の周りでは、なぜかSeleniumが流行っている模様です。 私自身は、Webアプリ的なのも作ってますが、あまり使ってなかったので、使ってみようと思います。 前回作成した、Djangoのupload_ …

no image

GLP-1 メディカルダイエット 58日目

メディカルダイエットして58日目の記録をしておこうと思います。 9回目。 今回は左腹(中部)に打ちました。痛いのはいまだに慣れない。。 土曜にゲットしてした 渋谷に行ってきたが、そこの医院には相変わら …

小ネタ: Ansible , with_itemsをloopに変える方法

とっても小さい小ネタです。 Ansible 2.4(今現在) -> Ansible 2.9に変えたい Ansibleを使用していますが、だいたい2.4ぐらいを使っています。流石にバージョンアップしない …

Djangoアプリサンプル – 画像ファイルアップロード + 顔モザイク(統合編)

顔モザイク Djangoアプリ 前々回 前回 を統合して、Djangoアプリを作成してみようと思います。 前提インストール 前回、ubuntu 18を前提に記述しましたが、CentOS7(CentOS …

Python3 – django-webtest

忙しいので断片だけ。。 DjangoでWebブラウザからアクセスする感じでテストする、やり方の一つです。以前にやったように、 Seleniumからやってもいいのすが、そこまでじゃない場合の単体テスト方 …

google オプトアウト Click here to opt-out.