Help us understand the problem. What is going on with this article?

Python SQLAlchemyとmarshmallowを使ってjson出力できるAPIを実装する

More than 1 year has passed since last update.

概要

FlaskによるWEBアプリケーションで最も使われるORMはSQLAlchemyだと思っていますが、SQLAlchemyによって実装されたModelをjsonify等を使ってjsonに変換しようとすると直接変換することができません。
この場合、Marshmallowを活用すると簡単に実装することが可能なのですが、意外と日本語記事が少なかったのでまとめてみました!

また今回の実装コードはgithubにて公開しています。

環境

  • OS: Windows 10
  • Python: Python 3.6.6 (Anaconda custom)
  • DB: MySQL 8.0.12
  • Framework: Flask 1.0.2
    ※仮想環境はpipenvを使用

アプリの実装

かの有名なFlask Tutorialをベースに実装していきます。

初期準備

Tutorialをベースに各ファイルを作成していきます。各ファイルの記述はTutorial通りにやればはまらないはず。

ディレクトリ構成
C:.
│  manage.py
│  Pipfile
│  Pipfile.lock
│  
└─flaskr
    │  config.py
    │  models.py
    │  views.py
    │  __init__.py
    │  
    ├─static
    │      style.css
    │      
    └─templates
            layout.html
            show_entries.html

DB(MySQL)との連携

参考までに記載しておきます。
まず、pymysqlをインストールします。

pipenv install pymysql

config.pyの接続情報を下記のように更新します。

config.py
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:password@localhost/DBname?charset=utf8'
SECRET_KEY = 'secret_key'
SQLALCHEMY_TRACK_MODIFICATIONS = True

また、__init__.pyの

__init__.py
from flask.ext.sqlalchemy import SQLAlchemy

の部分を下記の通りに変更すると無用なエラーがでません。

__init__.py
#from flask.ext.sqlalchemy import SQLAlchemy
#↑はエラーがでる
from flask_sqlalchemy import SQLAlchemy

接続テスト

コマンドプロンプト上でPythonを起動し、下記のコマンドをうつとMysqlの任意のDB内に"entries"というテーブルができます。

>>> from flaskr.models import init
>>> init()

画面での確認

Tutorialの記事を参考にしながら投稿データを作成し、下記のコードをコマンドプロンプト上に入力し、サーバーを起動してみてください。

python manage.py

そしてhttp://127.0.0.1:5000にアクセスするとブログの画面が出てくるはずです!

APIの実装

では本題のAPIの実装を行っていきます。
概要にも書きましたが、今回はMarshmallowとその関連パッケージを使用してAPIを作成していきます。

関連パッケージのインストール

3種類のパッケージをインストールします。

pipenv install marshmallow
pipenv install flask_marshmallow
pipenv install marshmallow-sqlalchemy

初期化ファイルの更新

__init__.pyを更新し、作成したmodelをjsonに変換するスキーマを定義します。
Marshmallowを使用する場合、maでスキーマを定義するのが一般的(らしい)。

__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

app = Flask(__name__)
app.config.from_object('flaskr.config')

db = SQLAlchemy(app)
ma = Marshmallow(app)

import flaskr.views

API連携用のModelの作成

API用のModelを定義します。
Tutorialで作成したEntryクラスを使用して、Marshmallowのスキーマを定義します。
SQLAlchemyを使用している場合、Metaで指定してあげるだけなので簡単!

models.py
from flaskr import db, ma
from marshmallow_sqlalchemy import ModelSchema

#DBのモデリングを行ったModel-----------------
class Entry(db.Model):
    __tablename__ = 'entries'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.Text)
    text = db.Column(db.Text)

    def __repr__(self):
        return '<Entry id={id} title={title!r}>'.format(
                id=self.id, title=self.title)

#json変換用----------------------------------
class EntrySchema(ma.ModelSchema):
    class Meta:
        model = Entry

API用のURL(View)の作成

API用のURLをviews.pyに作成していきます。
今回はAPIにリクエストを渡す⇒jsonで内容が返ってくる、ということをしたいので、下記のように更新していきます。

views.py
from flask import request, redirect, url_for, render_template, flash, jsonify
from flaskr import app, db, ma
from flaskr.models import Entry
from flaskr.models import EntrySchema

#ブラウザから見れる画面用-------------------------------------------------------
@app.route('/')
def show_entries():
        entries = Entry.query.order_by(Entry.id.desc()).all()
        return render_template('show_entries.html', entries=entries)

#json変換用(API)----------------------------------------------------------------
@app.route('/api', methods=['POST'])
def show_entries_json():
        entries = Entry.query.order_by(Entry.id.desc()).all()
        entries_schema = EntrySchema(many=True)
        return jsonify({'entries': entries_schema.dump(entries).data})

entries_schema = EntrySchema(many=True)

DBに複数のレコードが入力されている場合、many=Trueを指定してあげないとレコードが返ってこなくなってしまうので注意です。

テスト

うまく実装できているかテストを行います。
テストにはPostmanというAPIの確認を行えるツールを使います。
サーバーを起動させて、http://127.0.0.1:5000/apiのリクエストをsendしてみてください。
うまくいっていれば画面下部にjsonデータが返ってきているはずです!

entriesのデータ
{
    "entries": [
        {
            "id": 1,
            "text": "text",
            "title": "title"
        }
    ]
}

まとめ

SQLAlchemyを使用している場合、シンプルなmodelならばそれほど時間をかけることなくjson変換をすることができました。 使いどころとしてはサーバーサイドがFlask、フロントサイドはVue.jsなどのSPAで開発がしたい!という場合、けっこう有用かと思います。

ただmodelが多くなってくると、その分定義するスキーマも多くなっているので、管理のためにはファイルを分けるなどを検討してほうがよさげですね。

参考

公式のドキュメントリンクを記載しておきます。
- flask-marshmallow: https://flask-marshmallow.readthedocs.io/en/latest/
- marshmallow-sqlalchemy: https://marshmallow-sqlalchemy.readthedocs.io/en/latest/
- marshmallow: https://marshmallow.readthedocs.io/en/3.0/index.html

voygerrr
製造業の情シス担当。 予測モデルの開発や、データベースの開発とかやっています。 趣味でDjango/Vue.js使ってWEBアプリも勉強中。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away