DjangoでAPIサーバー作成⇨React(axios)で取得して表示
Django REST Framework
でAPIサーバーを作る初心者の入門記事として書きます。
前回記事までで、ReactでJSON PlaceholderでAPIをデータを取得しました。
JSON Placeholderで取得できるのと同じデータをDjango REST Framework
を使ってAPIサーバーを作り、Reactで表示させようと思います。
React & Material UI & Django RestFramework記事一覧
内容 | |
---|---|
part1 | React Material UIを使ってみる |
part2 | 【初心者】#2 React axiosでAPI データ取得 |
part3 | 【React初心者】 #3 ルーティング・ページ遷移を作る! react-router-dom |
part4 | 【Python】 Django REST Framework ReactとAPIサーバー繋ぐ ← ココ |
JSON Placeholderデータ確認
一応どんな感じのデータか確認する場合は以下で確認してください。
/posts
: 記事全部取得
/posts/:id
: 個別記事取得
これと同じデータ取得できるようなAPIサーバーをDjango REST Frameworkで作ります。
Django導入
私は今回、pipenvで作ろうと思います。
環境の準備が難しい場合は、anaconda入れるといいと思います。
好きなところにディレクトリ作って開始します。
$ pip install pipenv
$ pipenv --python 3.8.7
Pythonのバージョンを指定してます。
2020年の年末Djnagoを少しいじってたら、3.9だと動かないライブラリあったので3.8系を使ってます。
※ 以下pipenv
を使用しますが、anacondaやDockerなど他の環境でやるときはpip install
してください。
$ pipenv install django
$ pipenv install djangorestframework
仮想環境pipenvで作業
pipfile
が置いてあるところで、仮想環境の中に入ります。
普段、作業を開始するときはここから開始。
$ pipenv shell
一応確認。
$ python -V
Python 3.8.7
djangoのプロジェクトとアプリを作成
backendというプロジェクトを作成。
最後の.
はカレントディレクトリにプロジェクト作成すると言う意味。
アプリの名前はapi
という名前にします。
プロジェクト名も、アプリ名も好きに決めてください。
$ django-admin startproject backend .
$ django-admin startapp api
サーバー起動
manage.pyがあるところで、以下のコマンド実行
$ python manage.py runserver
デフォルトでは以下でサーバーが起動します。
ポート変更したかったら、
python manage.py runserver 7000
ブラウザでURLにアクセスして、ロケットが飛んだらOK
設定変更
日本語表示と、タイムゾーンを変更します。
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
INSTALLED_APPS = [
...
'rest_framework',
'api.apps.ApiConfig',
]
あとは、シークレットキーなど隠す必要ある方は、一番最後の
補足: python-dotenvで環境変数を設定
を見て設定してみてください。
ルーティング urls.py
アプリごとにurls.pyを作って管理した方が良いのでurls.pyを作ります。
$ touch api/urls.py
↓まだ記述が足りないです。後で付け足します。
from django.urls import path, include
from rest_framework import routers
router = routers.DefaultRouter()
urlpatterns = [
path('', include(router.urls)),
]
includeを足してアプリ(api)側に作ったurls.pyのルーティングを反映させる。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')),
]
model作成
今回とりあえず必要なのは、
id, title, body
です。
idはデフォルトで作られるので、title
, body
を作ります。
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=50, blank=False)
body = models.CharField(max_length=4000, blank=False)
def __str__(self):
return self.title
max_lengthは最大何文字にするかです。テキトウに決めました。
def __str__(self)
にself.title
と書くことで、
あとで、どんなデータか、タイトルのデータ表示で見やすくなるので設定しておいた方がいいと思います。
必須ではないです。
モデルにDBの構造を書いたので、makemigrations
でマイグレーションファイルを作成して、
マイグレーションファイルの記述通りにDBを作るため、migrate
します。
$ python manage.py makemigrations
$ python manage.py migrate
これで、DBにテーブルが作成されました。
シリアライザーを作る
データの加工とか、形式正しいかとかの処理をするのがシリアライザーです。
とりあえず、やってみないとピンとこないと思うので作ってみましょう。
$ touch api/serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'title', 'body']
使用するモデルがPostなのでmodel = Post
id, title, body
をReactに渡すので、
fields = ['id', 'title', 'body']
例えば、Reactでid, title
だけでいいなら
fields = ['id', 'title']
になります。
必要なデータだけ選択するようにします。
views.py設定
DjangoはMVC(Model View Controller)モデルでなくMVT(Model View Template)です。
DB関係を扱う「Model」、
HTMLっぽい記述をする「Template」
「Views」は、その二つの間でデータを処理・加工など両者の受け渡しというか、、、
そんな感じです。
ViewsがMVCのControllerに当たるもので、なんか紛らわしいですね。
とりあえず、ModelViewsetというのを使うと、CRUD(Create Read Update Delete)を少ない記述で簡単に作れますので使ってみます。
(記述量増えるけど、細かく処理させたいこと決めたいならAPIviewとか使う)
とりあえず、Postテーブルに登録されているデータを全部JSONとして返すコードを書きます。
↓
from django.shortcuts import render
from rest_framework import viewsets
from django.http import HttpResponse
from .serializers import PostSerializer
from .models import Post
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
admin管理画面に入る
情報を取得しようとしても、今は、DBに何もデータがありません。
これでは、データが取得できたかわからないですね。
ということで、管理画面を設定します。
Djangoの管理画面を作る
Djangoの管理画面は最初から付属しています。
簡単にデータを追加・修正したり、ユーザーを追加したりすることができます。
from django.contrib import admin
from .models import Post
admin.site.register(Post)
作成したmodelをインポートして登録しましょう。
これで管理画面で確認、追加、編集、。削除などできます。
管理画面に入る
ユーザーを作っていないと入れないですね。
コマンドでスーパーユーザーを作成します。
$ python manage.py createsuperuser
ユーザー名、メール、パスワードを設定してユーザーを作成します。
テストですので、簡単なパスワードでもいいと思います。
Bypass password validation and create user anyway? [y/N]:
みたいにパスワード単純すぎるよ!みたいなこと言われるけど、無視してy
入れていいです。
※ デプロイするときは、単純なパスワードは避ける
作成したユーザーでログインしてください。
モデルの名前である、
「POST」をクリック ⇨ 右上の「Postを追加」
押して、データを追加します。
そうしたら、以下のような登録フォーム出るのでデータを追加します。
データを何個か追加してみてください。
DBにデータが追加されます。
ルーターに追加
最後に、ルートを追加します。
from django.urls import path, include
from rest_framework import routers
from api.views import PostViewSet
router = routers.DefaultRouter()
router.register('posts', PostViewSet)
urlpatterns = [
path('', include(router.urls)),
]
router.register('posts', PostViewSet)
postsというURLに割り当てるのは、
views.pyに書いた、PostViewSet
の処理という意味です。
紛らわしいですが、元からあったurls.pyには
path('api/', include('api.urls')),
と書いたので、
api/
というURL以降にapiフォルダの方にある、urls.pyの記述を足します。
ということで、api/
+ posts
なので
にアクセスするとAPIサーバーからデータを取れることになります。
処理の流れ
- APIを叩かれる。URLが
http://127.0.0.1:8000/api/posts/
- views.pyに書いてある
PostViewSet
の処理が実行 -
queryset = Post.objects.all()
でPostテーブルからデータを全て取得- SQLなら
SELECT * FROM POST
みたいな感じ。正確にはDBのテーブル名違うけど
- SQLなら
- シリアライザーでデータを整える。
- 今回は、単純な処理なので、処理はほぼしていない。
- いらないカラムデータを削除(fieldsで指定したりする)、データを加工してJSONにするとかできる
- 例えば、2021-01-17 12:00:00が見にくいから、2021年1月17日にしてJSONデータ作るとか
- JSON形式でDjangoのAPIサーバーがデータを送信
少し長くなりましたが、これでできました。
URLにアクセスすると、
以下のように先ほど管理画面で登録したデータを取得できているのがわかります。
Postmanで取得してみる
インストールしてない人はここから
APIを叩く(APIサーバーからデータもらう)ときによく使われるツールです。
先ほど確認できたので、大丈夫ですが、一応体験しましょう。
今回はGetで取得しますね。
手順
create request ⇨ URL入れる ⇨ Send
認証のトークンをつけてAPIを叩いたり、
POSTデータを送信することもできるなどなど便利ツールです。
(今回はあまり使う意味なかったけど、WEBアプリ開発するなら入れておきましょう。使います。)
これだけだと、Reactで読み込めない
一見良さそうなんですけど、セキュリティとかの関係で今のままだと、
ReactではAPIを叩いてもデータを取得できません。
必要なものをインストールして、設定をします。
$ pipenv install django-cors-headers
設定が必要なので、以下を追加します。
INSTALLED_APPS = [
'corsheaders', # 追加
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 追加
]
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:3000',
'http://localhost:3000',
]
CORS_ALLOWED_ORIGINS
は通信を許可するIPとポートを指定する設定です。
Reactのデフォルトで起動するのはhttp://localhost:3000
ですのでこのように書いてます。
localhostのIPの設定は意図的に変更しない限り、127.0.0.1
なので一応書いてます。
※ CORS_ORIGIN_WHITELIST
で指定するという情報がありました。
最近のバージョンではCORS_ALLOWED_ORIGINS
ですので注意。
一応ちゃんと確認したい方は、リポジトリを見てください
Djangoはこれで完成です!🎉
ReactからDjangoのAPIサーバーにアクセス
※ こちらは前回作ったReactの続きです。
こちらはそれほどやることはなくて、URLを変更すれば良いだけです。
function Content() {
const [post, setPosts] = useState([])
useEffect(() => {
// axios.get('https://jsonplaceholder.typicode.com/posts')
axios.get('http://127.0.0.1:8000/api/posts/')
.then(res => {
setPosts(res.data)
})
}, [])
const getCardContent = getObj => {
const bodyCardContent = {...getObj, ...cardContent};
return (
<Grid item xs={12} sm={4} key={getObj.id}>
<BodyCard {...bodyCardContent} />
</Grid>
);
};
return (
<Grid container spacing={2}>
{post.map(contentObj => getCardContent(contentObj))}
</Grid>
)
}
BodyCard.js
でconst { userId, id, title, body, avatarUrl, imageUrl } = props;
と書いてあって、ここにデータが渡ります。
userIdは今回作っていませんが、もともと使っていなかったので表示には問題ないです。
(※ 消してもよかったですね…)
Reactサーバー起動
Reactを開発したディレクトリにて、サーバーを起動して、
$ npm start
URLにアクセスすると、
うまくいけば、表示されます。
Djangoの管理画面でデータを登録したら増えますので試してください。
APIで個別記事のデータ取得
次は、「詳細をみる」ボタンで表示される個別の詳細記事です。
実は、ModelViewSetを使うと一通りの機能を作ってくれているので、すでに完成しています。
とブラウザのURLのところに入れれば、データが表示されます。
ついでに、コード書いてないですが、削除、変更もすでに実装されています。
DELETE、PUTのボタンありますよね。この画面のボタンを押しても、編集できますし、
Postmanで、HTTPの通信を使って、
消したり、変更したりを、所定の形式に従って送ってやれば実行されるAPIが完成してるんですね。
まあ、今のうちは、ModelViewSet
使うと簡単にCRUD作れるんだねー
くらいで良いと思います。
Reactからこの個別記事詳細データを取得
前回の
[【初心者】React #3 ルーティング・ページ遷移 react-router-dom]
ですでにボタンから個別の記事に飛べるようにもなっていますので
API叩くためのURLを変えるだけでOK
import React, {useState, useEffect} from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom'
import { Grid } from '@material-ui/core'
import BodyCard from './BodyCard'
const cardContent =
{
avatarUrl: "https://joeschmoe.io/api/v1/random",
imageUrl: "https://picsum.photos/150"
}
function PostContent() {
const { id } = useParams();
const [post, setPosts] = useState([])
useEffect(() => {
// axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`)
axios.get(`http://127.0.0.1:8000/api/posts/${id}`)
.then(res => {
setPosts(res.data)
})
}, [])
return (
<Grid container spacing={2}>
<Grid item xs={12} key={post.id}>
<BodyCard {...{...post, ...cardContent}} />
</Grid>
</Grid>
)
}
export default PostContent
URLを変えるだけで詳細ページはOKです。
一覧表示のBodyCardコンポーネント
をそのまま使ったので
「詳細をみる」ボタンはここには必要ないし、画面の引き伸ばし感がひどいですが、
個別記事のルーティングもできていますね
まとめ
- Django Rest Frameworkを使ってAPIサーバーを作成
- Reactから作成したAPIサーバーにアクセスできるようにDjangoで設定
- Reactで作成したAPIサーバーからデータが取得できることを確認
補足: python-dotenvで環境変数を設定
必須ではないです。必要な人はやってみましょう。
githubなどにpublicで公開するとき、APIキーなど公開すると危険な情報はを.envに書き、.gitignore
で除外しましょう
やり方よく忘れるので、メモしときます。
デプロイするものなどは、githubのpublicにしないか、
公開したらやばいものは公開しないようにしてください。
環境変数を.env
から読めるようにします。
$ pipenv install python-dotenv
プロジェクト直下、manage.pyとかと同じところに.envファイル作って、ここにみられたえらやばい情報を追加します。
$ vim .env
SECRET_KEYと、DEBUGも一応追加しておきます。
setting.py
に書いてある、SECRET_KEYと、
ついでにDEBUGの値を以下のように貼り付け。
SECRET_KEY=1234567890asdfghjklwertyzx
DEBUG=True
.envから読み込む記述と、
SECRET_KEY
, DEBUG
をos.getenv('ここに.envに書いた名前書く')
にする。
import os
from dotenv import load_dotenv
load_dotenv(verbose=True)
dotenv_path = os.path.join(BASE_DIR, ".env")
load_dotenv(dotenv_path)
SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = os.getenv('DEBUG')
.gitignore作ってなかったら、.envと同じプロジェクト直下に作成して以下の記述を足してください。
ついでに.githubのリポジトリ作るときに、.gitignoreを追加⇨python選べば、
こんな感じの記述はすでに書かれていると思うのでその場合は不要です。
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
.gitignoreに追加すれば、変更を追跡しなくなるので、
うっかり後悔すると問題になる情報をgithubに公開してしまった!
ということはなくなります。
今回はDjangoのSECRET_KEYで、テストアプリなので公開しても特に問題はないと思います。
ただAPIキー、特にAWS関係の情報を晒したら、悪用されて多額の請求来ます!
隠したいファイルはあるけど、プロジェクトはgithubに公開しないといけないときには使いましょう。
React & Material UI & Django RestFramework記事一覧
内容 | |
---|---|
part1 | React Material UIを使ってみる |
part2 | 【初心者】#2 React axiosでAPI データ取得 |
part3 | 【React初心者】 #3 ルーティング・ページ遷移を作る! react-router-dom |
part4 | 【Python】 Django REST Framework ReactとAPIサーバー繋ぐ ← ココ |