環境構築にから順々に記載しています。
Djangoプロジェクトの作成は5.2.Djangoプロジェクトの作成から、具体的な実装内容等は次回記事になります。
■やったこと
コロナの影響で買えなくなってしまった商品の入荷情報を定期+任意のタイミングでチェックして、その内容を通知するLINE Botを作りました。
(今回の記事はフレームワークの紹介のみです)
■想定している読者
・Python初学者(開発経験あり)
・web APIを作ってみたいという方
・LINE Botを作ってみたいという方(この内容は次回です)
誰にでも"とりあえず"実装できるような記事を目指しています。
何をやっているのかわからないという状況を避けるべく、周りくどい表現や冗長な表現が多用されると思いますが、何卒ご容赦ください。
また、理解が完璧ではないので一部ふわっとした説明になっています。
あくまでも同じことが出来るようになる、ということに重点を置いています。
■開発環境
OS
・Windows 10
Python
・python3.6.4
主なライブラリ
・django
・djangorestframework
・selene
WEBサーバ
・Heroku
DB
・PostgerSQL
・MySQL(ローカルでのみ使用)
エディタ
・visual studio code
その他
・Advanced REST Client
■開発準備
1.Pythonのインストール
Pythonをインストールしていない場合は、こちらなどを参考にインストールします。
一応3.6.4を使いましたが、ローカルで使うには最新版でも問題ありません。
2.仮想環境の作成
コンソール上で、アプリを作成したいディレクトリに移動し、以下のコマンドを実行します。
完了時のメッセージはありません。
python -m venv venv
正常に実行されると、コマンドを実行したディレクトリにvenvフォルダが作成されます。
venv/Scripts
に移動し、activate.bat
を実行します。
実行すると、コンソールの表示が以下のように切り替わります。
(venv) C:\(作成したいディレクトリ)\venv\Scripts>
(venv)と表示されていれば成功です。これで無事仮想環境に入ることができました。
※仮想環境とは?という方はこちら
3.ライブラリのインストール
仮想環境に必要なライブラリをインストールしていきます。
以下のコマンドを打てば終わりです。Djangoのインストールにはちょっとだけ時間がかかります。
pip install django
pip install djangorestframework ※1
pip install selene
※1
django-rest-frameworkではないので注意
memo:
pipはPythonにおけるパッケージマネージャです。
他にもpipenv,Poetry,Pyflowなどといったパッケージマネージャがあり、そちらの方が高機能なようですが、
実際に使うところまではできていないのでご紹介程度に…
4.MySQLの準備
MySQLをローカルにインストールしていない方はこちらなどを参考にインストールしてください。
MySQLを使用せず、sqliteでよいという方はこちらの手順を飛ばしていただいても問題ありません。
5.プロジェクトの枠作り
5.1.DjangoプロジェクトおよびDRFについて
DRFはDjangoプロジェクトの上に成り立っています。
DjangoはMTVモデルに従って作成します。Model・Template・Viewモデルです。
MVCモデルと対応させると"おおよそ"以下の通りです。Viewが知っている役割をしていなかったので、最初は本当に混乱しました…
MVC | MTV | MTVについての備考 |
---|---|---|
Model | Model | DBのテーブルと1対1になる。DBと連携する。 |
View | Template | HTMLファイル。Viewで処理されたデータを表示する。 |
Controller | View | Modelで取得したデータやリクエストで渡されてきたデータの処理を記述する。 |
そして、今回使用するDRFではTemplateは使用しません。
DRFは以下の構造で成り立っています。(正確な図ではないかもしれませんが、ざっくりこんな感じです。)
5.2.Djangoプロジェクトの作成
では、djangoプロジェクトを作成していきます。
プロジェクトのルートディレクトリにしたい位置に移動して、以下のコマンドを実行します。
django-admin startproject sample_project
これでsample_projectという名前のプロジェクトのひな形が作成されます。
作成されたsample_projectのsettings.pyにrest_frameworkを使用することを追記します。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # 追記箇所
]
さらに、sample_project内で以下のコマンドを実行します。
python manage.py startapp sampleapp
これでsample_projectにsampleappが作成されます。
先ほど同様、settings.pyにsampleappを追記します。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'sampleapp', # 追記箇所
]
すぐには必要になりませんが、sample_projectのurls.pyに以下のように追記しましょう。
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^sampleapp/', include(sampleapp_router.urls)), # 追記箇所
]
これは、http://(ホスト名)/sampleapp/ にアクセスされたときにはsampleapp/urls.py
が呼ばれるようにしています。
先ほどの図では省略していましたが、DjangoプロジェクトにはUrls.pyがプロジェクトレベルのものとアプリレベルのもので2つ存在しており、以下のような関係になっています。
おまけで、LANGUAGE_CODEとTIME_ZONEも以下のように修正します。
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
5.3.ローカルサーバーの起動
仮想環境内で以下のコマンドを実行します。
python -m manage.py runserver
これで、ローカルサーバーが起動します。以下のURLにアクセスしてみましょう。
http://localhost:8000/
welcomeページが表示されるはずです。
ちなみに、サーバーはコマンドプロンプトでctrl+cをすれば停止します。
ここまでで、プロジェクトの大枠は作ることができました。
5.4.管理者ページについて
djangoプロジェクトには管理者ページが存在します。
このページはdjangoプロジェクトを作成すると自動で提供されますが、今回は特に使用しません。
管理者ページについて気になる方は別途お調べください…
5.5.MySQLを使用する方へ
mysqlclinetのインストールと、settings.pyを修正してください。
pip install mysqlclient
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
# 上記のsqliteを使用する設定を以下の内容に修正
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '(使用するDBのスキーマ名)',
'USER': '(ユーザ名)',
'PASSWORD': '(パスワード)',
'HOST': '(ホスト名)',
'PORT': '(ポート番号)',
}
}
6.実装
プロジェクトの大枠を作ることが出来たので、具体的な実装に入っていきます。
6.1.modelの追加
sampleapp/model.py
にDBに追加したいテーブル単位でmodelを記載していきます。
class=テーブルという関係になり、ORM的な働きをします。試しにUserモデルを作成します。
from django.db import models
class User(models.Model):
user_id = models.CharField(max_length=128)
age = models.TextField()
user_name = models.TextField()
bithday = models.DateTimeField()
password = models.CharField(max_length=128)
以下の形で記述されています。
カラム名 = データ型(制約の指定)
※データ型の指定方法については、こちらが詳しいです。
6.2.マイグレート
先ほどmodel.pyに記載した内容で、DBをマイグレートします。(ここではテーブルを新たに作成)
マイグレーションファイルを作成するために、仮想環境内で以下のコマンドを実行します。
ローカルサーバーを動かしている場合は、ctrl+cで一度止めましょう。
python manage.py makemigrations sampleapp
作成されたファイルの中身を確認するためには以下のコマンドを実行します。
python manage.py sqlmigrate sampleapp 0001
実際にマイグレートするには以下のいずれかのコマンドです。
python manage.py migrate sampleapp : 実行されていないファイル全てを実行する
python manage.py migrate sampleapp 0001 : 実行したいファイルを指定する書き方
これで、models.pyに記載した内容でテーブルが作成されています。
各コマンドの後ろに打っている"0001"は、マイグレーションファイルのシリアル番号です。
テーブルの追加や定義の変更のために新たにマイグレーションファイルを作るごとに新たにファイルが作成されるので、当然ですが毎回必ずマイグレートする必要があります。
6.3.seriaizer定義
ModelやDtoをjson形式にシリアライズしたり、jsonをデシリアライズしたりするのがserializerです。
sampleappディレクトリに、serializer.pyを作成してください。
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User # シリアライズ対象のModelを指定します
fields = ('user_id', 'age', 'user_name', 'bithday', 'password') # Userクラスに定義したフィールド名を書きます
class UserEncryptSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('user_id', 'age', 'user_name', 'birthday', 'password')
def create(self, validated_data):
user = User(
user_id = validated_data['user_id'],
age = validated_data['age'],
user_name = validated_data['user_name'],
birthday = validated_data['birthday'],
password = encrypt(validated_data['password']) # 暗号化している風の処理
)
user.save()
return user
createメソッドはModelSerializerクラスに定義されているメソッドで、オーバーライドしています。
createメソッドに渡したデータ(validated_data)をUserインスタンスにセットして、DBにinsert(save)します。
UserSerializerとUserEncryptSerializerがありますが、どちらのクラスも使い方は同じになります。
各クラスの違いは、createメソッドをオーバーライドしているかどうかだけです。
オーバーライドすることで、シリアライズされたデータを加工してからinsertができます。
例ではパスワードを暗号化している風のことをしています。
これでSerializerはOKです。
memo:
class Metaとありますが、こちらはPythonのMetaクラスとはまた別の概念のようです。今回はModelSerializerを継承しているため、Modelをシリアライズ(デシリアライズ)するためのクラスになりますが、継承するものによって扱えるデータや扱い方が異なります。
6.5.viewを記述
次に、sampleapp/views.py
にデータの処理を書いていきます。
import django_filters
from rest_framework import viewsets, filters
from django.core import serializers
from .models import User
from .serializer import UserSerializer, UserEncryptSerializer
import json
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
class AdultUserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.filter(age__gte=20)).order_by('-age')[:8]
2つの簡単なViewを作成してみました。
それぞれに共通して書かれているserializer_class
とqueryset
はDRFで予め定義されている変数です。
ModelViewSetを継承したクラスでは必ず記載する必要があります。
serializer_classには使用するSerializerを代入します。
querysetは、DBからどのようにデータを取得するかを取得します。
AdultUserViewSetのquerysetは以下のSQLと同等の内容になっています。
select * from user where age >= 20 order by age desc
あまり複雑なクエリは書けないようですが、そのような場合はSQLAlchemyというORMライブラリを使用すると良さそうです。
私は今回使用していないので、ご紹介程度です…
ちなみにこれだけのコード量ですが、userテーブルに対するCRUD処理が一通り実装されています。
今回のBotを作るにあたってはそこまで恩恵に預かれませんでしたが、これは本当に手軽ですね…
ここまでくればあと一歩です!
7.URLを設計
先ほどはプロジェクトレベルのurls.py
に手を入れて、http://(ホスト名)/sampleapp/
にアクセスされた際にsampleapp/urls.py
が呼び出されるようにしました。
次に、アプリケーションレベルのurls.py
に手を入れます。
from rest_framework import routers
import sampleapp.views as view
router = routers.DefaultRouter()
router.register('user', view.UserViewSet)
router.register('user/adult/', view.AdultUserViewSet)
これで、http://(ホスト名)/user/
にアクセスされればUserViewSetが呼び出され、http://(ホスト名)/user/adult/
にアクセスされればAdultUserViewSetが呼び出されます。
8.レスポンスの確認
curlコマンドやAdvanced REST Clientを使ってCRUD処理が実装されていることを確認しましょう。
こちらの説明は一旦省略しますが、時間があるときに追記するかもしれません。
7.URLを設計までを読んでいれば次回の内容も問題無く読めるとは思います。
9.まとめ
これで、DRFについてのチュートリアルレベルの、かなり嚙み砕いた説明は終わりです。
DRFの概説だけでも結構な量になるため、記事を分割します。
次回は具体的な実装内容と、Herokuへのデプロイ手順、LINE Botの作成手順です。
■参考資料
Django ドキュメント
Django REST Frameworkのチュートリアル
[Django REST Framework] View の使い方をまとめてみた
Django REST Frameworkを使って爆速でAPIを実装する