はじめに
メシウスはHTML/CSS、JavaScriptで実装するWebページ向けに複数のライブラリを提供しています。ActiveReportsJSは帳票ライブラリ、WijmoはさまざまなUI部品を提供するライブラリです。
Webアプリでは一般的に、Webページで表示するデータはWeb APIを利用してサーバーから取得します。そのためActiveReportsJSやWijmoも、Web APIを提供するサーバーと組み合わせることで、より実用的に活用できます。
そこで本記事では、ActiveReportsJSやWijmoを、サーバー側のWeb APIと組み合わせて利用する方法を、2回に分けて説明していきます。初回となる今回は、PythonベースのWebアプリケーションフレームワーク「Django」でWeb APIを開発できるライブラリ「Django REST framework」を利用して、サーバー側のWeb APIを作成していきます。次回は、ActiveReportsJSやWijmoをReactと組み合わせて作成したWebページで、今回作成するWeb APIから取得したデータを表示します。
対象読者
- ActiveReportsJSやWijmoの、実利用により近いサンプルを必要としている方
- Web APIを手軽に実装したい方
- Pythonの環境構築や実装手順を体験してみたい方
必要な環境
本記事のサンプルコードは、以下の環境で動作を確認しています。XAMPPは、MySQLデータベースを実行するために利用します。
- Windows 10 64bit版
- Python 3.11.5
- XAMPP 8.2.4
サンプルコードを実行するには、必要なライブラリがインストールされた仮想環境を有効にした後、プロジェクトフォルダーで「python manage.py runserver」コマンドを実行して、Webブラウザーで「http://localhost:8000」を表示します。仮想環境やコマンドなど、実行方法の詳細は後述します。
Web APIを実装する環境を作ろう
以下では、Pythonの環境にDjango REST frameworkをインストールして、Web APIのプロジェクト・アプリケーションを構築する手順を、順を追って説明していきます。Pythonは公式ページからダウンロードしたインストーラーを実行してインストールしておきます。
仮想環境の作成と有効化
Web APIのプロジェクトでは、Django REST frameworkをはじめさまざまなライブラリを利用しますが、特に意識しないとそれらはシステム自体にインストールされるため、複数プロジェクトで異なるバージョンのライブラリを使い分ける場合に問題になります。
そこでPythonでは、ライブラリをインストールするための「仮想環境」を作成し、そこにライブラリをインストールして利用できます。仮想環境を作成するコマンドはリスト1の通りです。
py -m venv myvenv
「py」は、Windowsにインストールされている適切なPythonを実行する「Pythonランチャー」です。「-m venv」はvenvモジュールを意味し、「myvenv」は作成する仮想環境の名前です。このコマンドで、myvenvフォルダーに仮想環境が生成されます。
作成した仮想環境はコマンドで有効にする必要があります。コマンドラインにPowerShellを利用している場合、リスト2のコマンドを実行します。なおコマンドラインにコマンド プロンプト(cmd)を利用している場合は「Activate.ps1」の代わりに「activate.bat」を実行します。
myvenv\Scripts\Activate.ps1
仮想環境が有効になると、コマンドラインの先頭に仮想環境の名前「(myvenv)」が表示されます。
なお、Windowsのセキュリティ設定でリスト2の実行がエラーになる場合は、管理者権限で実行したPowerShellで「Set-ExecutionPolicy RemoteSigned」コマンドを実行すると実行できるようになります。詳細はPowerShellに関するマイクロソフトのドキュメントを参照してください。
ライブラリのインストールとプロジェクトの作成
次に仮想環境に、Web APIに必要なライブラリをインストールしていきます。リスト3のコマンドで、Django REST frameworkをインストールします。pipはPythonで利用できるパッケージマネージャーのコマンドです。
pip install djangorestframework
実行後、Django REST frameworkが依存するWebフレームワーク「Django」が提供する、django-adminコマンドが利用できるようになります。このコマンドをリスト4の通り実行して、p001basicプロジェクトと、その内部にp001basicappアプリケーションを作成します。
django-admin startproject p001basic cd p001basic django-admin startapp p001basicapp
Djangoのプロジェクトは複数のアプリケーションを保持できますが、p001basicプロジェクトには1つのアプリケーションp001basicappを追加しました。プロジェクトおよびアプリケーションを構成する各ファイルの説明は、サンプルコードのreadme.mdファイルに記述しているので参考にしてください。
Django REST frameworkを利用する指定
プロジェクトがDjango REST frameworkを利用する設定を、p001basic/settings.pyのINSTALLED_APPSに、リスト5の通り行います。
INSTALLED_APPS = [ 'django.contrib.admin', (略) 'rest_framework', # この行を追加 ]
マイグレーション(初期データの作成)
プロジェクトに含まれるmanage.pyはプロジェクト管理用のスクリプトで、プロジェクトに関するさまざまな処理を行えます。ここではリスト6のコマンドを実行して、マイグレーション(プロジェクトが利用するデータベースの初期化)を行います。この処理により、プロジェクトに必要なデータを含むSQLiteファイル(db.sqlite3)が生成されます。SQLite以外のデータベースを利用する方法は後述します。
python manage.py migrate
[補足]仮想環境を有効化したらpyコマンドは使わない
リスト6では、リスト1で利用したPythonランチャーpyは使わず、pythonコマンドを直接利用しています。これは、仮想環境の内部には仮想環境で利用するpythonコマンドが含まれており、仮想環境を有効化するとそのpythonコマンドに実行パスが設定されるためです。
Web API実装のポイントはシリアライザー、ビュー、ルーター
ここまででプロジェクトの環境が整ったので、最初のWeb APIを実装していきます。Django REST frameworkでWeb APIを実装するには、「シリアライザー」「ビュー」「ルーター」の3つを実装します。
Web API戻り値に含めるデータ項目を決めるシリアライザー
シリアライザーでは、プロジェクトが持っているデータベースから、APIで出力するテーブルとデータ項目を指定します。p001basicappフォルダー配下にserializers.pyファイルを作成して、リスト7の通り実装します。
#Userテーブルの内容を出力するシリアライザー ...(1) class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ['url', 'username', 'email', 'groups'] #Groupテーブルの内容を出力するシリアライザー ...(2) class GroupSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Group fields = ['url', 'name']
(1)のUserSerializerでは、Userテーブルから「url」「username」「email」「groups」の項目を出力するよう指定します。「url」は、そのデータを返却するAPIのURLです。同様に(2)のGroupSerializerでは、Groupテーブルから「url」と「name」の項目を出力するよう指定します。なお、UserテーブルとGroupテーブルは、Djangoプロジェクトに最初から定義されるテーブルで、リスト6のマイグレーションで生成されます。
Web APIの設定を行うビュー
ビューでは、Web APIの検索や表示に関する設定を記述します。p001basicapp/views.pyに、リスト8の通り実装します。
#User APIのビュー ...(1) class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() # ...(1a) serializer_class = UserSerializer # ...(1b) #Group APIのビュー ....(2) class GroupViewSet(viewsets.ModelViewSet): queryset = Group.objects.all() serializer_class = GroupSerializer
(1)がUserのビュー定義です。(1a)のquerysetは検索条件を表し、ここではUser.objects.all()メソッドで全オブジェクトを表示するようにします。(1b)は使用するシリアライザーで、リスト7(1)で定義したUserSerializerを指定します。Groupについても(2)で同様に実装します。
Web APIのURLを設定するルーター
最後にルーターの設定です。p001basic/urls.pyに、リスト9の通り実装します。
#ルーターの定義 ...(1) router = routers.DefaultRouter() #...(1a) router.register('users', views.UserViewSet) #...(1b) router.register('groups', views.GroupViewSet) #...(1c) #URLパターンの設定 ...(2) urlpatterns = [ path('', include(router.urls)) #...(2a) ]
ルーターの定義は(1)です。(1a)でルーターを生成し、(1b)で「users」というパスに対してリスト8(1)のUserViewSet、(1c)で「groups」というパスに対してリスト8(2)のGroupViewSetを割り当てます。(2)はURLパターンの設定で、(2a)で空文字(つまりすべてのURLパターン)に対してルーターのURLを利用するよう設定します。
Web APIを実行していろいろ試してみよう
それではここまで実装したWeb APIを実行してみましょう。manage.pyを利用してリスト10の通りコマンドを実行します。
python manage.py runserver
実行後、Webブラウザーでhttp://localhost:8000にアクセスすると、図4の通り表示されます。
まずGroupのWeb APIへのリンク「http://localhost:8000/groups/」にアクセスしてみましょう。画面上部にはAPIが返却するグループの一覧(この段階ではまだ空)が、画面下部にはグループを追加するテキストボックスが表示されます。テキストボックスに適当な名前を入力して「POST」をクリックすると、POSTのREST APIが実行されて、グループが追加されます。
同様に、UserのWeb API「http://localhost:8000/users/」にアクセスすると、画面上部にユーザーの一覧、下部にはユーザーを追加するためのフォームが表示されます。グループが追加されている場合、Groupsの欄に表示されて選択できます。
追加されたUserは、「http://localhost:8000/users/」にアクセスすると一覧表示されます。
このようにDjango REST frameworkでは、データの表示や追加といったWeb APIの処理を、Webページ上の対話的な操作で確認できます。
ActiveReportsJS/Wijmo用のWeb APIを実装しよう
ここからは次回に備えて、ActiveReportsJS/Wijmoでアクセスすることを想定したWeb APIを実装していきます。新規に「p002phones」プロジェクトと「p002phonesapp」アプリケーションを生成して、以下の実装を行います。
データを格納するモデル
最初のサンプルではDjangoがもともと持っているテーブルであるUser、Groupを対象にWeb APIを作りましたが、ここで作るサンプルでは、スマートフォンの機種を表す「Phone」と、そのベンダーを表す「Vendor」を独自に定義して利用します。データを格納するクラス(モデル)を、p002phonesapp/models.pyに、リスト11の通り記述します。
#Vendorモデル ...(1) class Vendor(models.Model): name = models.CharField(max_length=255) #...(1a) region = models.CharField(max_length=255) #...(1b) def __str__(self): return self.name # モデルの文字列表現 ...(1c) #Phoneモデル ...(2) class Phone(models.Model): name = models.CharField(max_length=255) #...(2a) price = models.PositiveIntegerField() #...(2b) vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE) #...(2c)
モデルは、models.Modelクラスを継承して定義します。(1)のVendorクラスでは、(1a)で最大255文字のname(名前)フィールドと、(1b)で最大255文字のregion(地域)フィールドを定義します。(1c)はオブジェクトの文字列表現で、ここではnameを指定します(この記述により、Web画面でモデル名が表示されます)。
(2)のPhoneクラスには、(2a)で最大255文字のname(名前)フィールドと、(2b)で正の整数からなるprice(価格)フィールドを定義します。(2c)のvendor(ベンダー)フィールドは、ForeignKey指定により、Vendorクラスのオブジェクトを指定します。「on_delete=models.CASCADE」は、Vendorのデータが削除されたときに、そのVendorが指定されたPhoneモデルも連動して削除されることを表します。
モデルを追加後は、モデルに対応するテーブルをデータベースに生成するマイグレーションが必要です。まず、追加されたモデルが認識されるよう、リスト12の通り、settings.pyのINSTALLED_APPSにp002phonesappアプリケーションを追加します。
INSTALLED_APPS = [ 'django.contrib.admin', (略) 'rest_framework', # Django REST frameworkの指定 'p002phonesapp', # この行を新たに追加 ]
設定後、リスト13のコマンドを実行して、マイグレーションの処理が記述されたマイグレーションファイル(p002phonesapp/migrations/0001_initial.py)を作成します。マイグレーションは後で実行します。
python manage.py makemigrations # 追加モデルのマイグレーションを作成
シリアライザー、ビュー、ルーター
追加したVendor、Phoneモデルに対して、シリアライザー、ビュー、ルーターの実装を追加します。実装内容はリスト7~9と類似しているので、詳細はサンプルコードを参照してください。
データベースをMySQLに変更
最初のサンプルでは、データベースはマイグレーション時に自動生成されるSQLiteデータベースを利用していました。このサンプルではより本格的なデータベースとして、MySQLデータベースを利用することにします。データベースの設定はsettings.pyにリスト14の通り記述します。ここではlocalhost上のMySQLデータベース「p002phones_db」に、ユーザー名「dbuser」、パスワード「password」で接続するように設定します。
DATABASES = { # ここがもともとあったSQLiteの設定 # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': BASE_DIR / 'db.sqlite3', # } # 以下がMySQLの設定 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'p002phones_db', # DB名 'USER': 'dbuser', # ユーザー 'PASSWORD': 'password', # パスワード 'HOST': 'localhost', # ホスト 'PORT': '3306', # ポート } }
また、MySQLデータベースを利用するために、リスト15のコマンドでドライバー(mysqlclient)をインストールします。
pip install mysqlclient
MySQLデータベースは、Windows上で動作するXAMPPを利用して動作させます。Webページからインストーラーをダウンロードしてインストール後、XAMPPコントロールパネルでMySQLを起動して、シェルを開きます。
シェル上で「mysql -u root」コマンドを実行してMySQLにログイン後、リスト16のコマンドを実行して、データベースとユーザーを追加します。
# データベースを作成 CREATE DATABASE p002phones_db; # ユーザーを作成 CREATE USER 'dbuser'@'localhost' IDENTIFIED BY 'password'; # ユーザーでデータベースが利用できるよう割り当て GRANT ALL PRIVILEGES ON p002phones_db.* TO 'dbuser'@'localhost';
MySQL側の準備が完了した後でマイグレーション(「python manage.py migrate」コマンド)を実行すると、MySQL上にテーブルが作成されます。SQLiteとMySQLの違いはフレームワークが吸収してくれます。
以上で、VendorとPhoneを利用したWeb APIができ上がりました。「python manage.py runserver」コマンドで実行してWebページを表示すれば、VendorやPhoneへのデータ追加や一覧表示が確認できます。
まとめ
本記事では、メシウスのライブラリであるActiveReportsJSやWijmoと組み合わせて使うWeb APIを、PythonのDjango REST frameworkを利用して作成しました。フレームワークが提供する基本的な機能や実装の大枠を利用して、プログラマーはWeb APIの内容に集中して実装を行えます。
次回はActiveReportsJSやWijmoをReactと組み合わせたサンプルで、今回実装したWeb APIにアクセスしてデータを表示する方法を説明していきます。