34
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Django REST Framework チュートリアル】#4 ReactとAPIサーバー繋ぐ【入門】

Last updated at Posted at 2021-01-29

DjangoでAPIサーバー作成⇨React(axios)で取得して表示

Django REST FrameworkでAPIサーバーを作る初心者の入門記事として書きます。

前回記事までで、ReactでJSON PlaceholderでAPIをデータを取得しました。
JSON Placeholderで取得できるのと同じデータをDjango REST Frameworkを使ってAPIサーバーを作り、Reactで表示させようと思います。
dajngo rest framework and react.jpeg

:pushpin: 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: 記事全部取得

https://jsonplaceholder.typicode.com/posts

/posts/:id: 個別記事取得

https://jsonplaceholder.typicode.com/posts/1

これと同じデータ取得できるようなAPIサーバーをDjango REST Frameworkで作ります。

Django導入

私は今回、pipenvで作ろうと思います。
環境の準備が難しい場合は、anaconda入れるといいと思います。

> Pipenv 環境構築方法

好きなところにディレクトリ作って開始します。

$ 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

デフォルトでは以下でサーバーが起動します。

http://127.0.0.1:8000/

ポート変更したかったら、
python manage.py runserver 7000

ブラウザでURLにアクセスして、ロケットが飛んだらOK

スクリーンショット 2021-01-16 20.48.33.png

設定変更

日本語表示と、タイムゾーンを変更します。

settings.py
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'api.apps.ApiConfig',
]

あとは、シークレットキーなど隠す必要ある方は、一番最後の
補足: python-dotenvで環境変数を設定を見て設定してみてください。

ルーティング urls.py

アプリごとにurls.pyを作って管理した方が良いのでurls.pyを作ります。

$ touch api/urls.py

↓まだ記述が足りないです。後で付け足します。

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のルーティングを反映させる。

backend/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を作ります。

api/models.py
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
django-react-material/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として返すコードを書きます。

django-react-material/api/views.py
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の管理画面は最初から付属しています。
簡単にデータを追加・修正したり、ユーザーを追加したりすることができます。

django-react-material/api/admin.py
from django.contrib import admin

from .models import Post

admin.site.register(Post)

作成したmodelをインポートして登録しましょう。
これで管理画面で確認、追加、編集、。削除などできます。

管理画面に入る

スクリーンショット 2021-01-17 1.04.38.png

ユーザーを作っていないと入れないですね。
コマンドでスーパーユーザーを作成します。

$ python manage.py createsuperuser  

ユーザー名、メール、パスワードを設定してユーザーを作成します。
テストですので、簡単なパスワードでもいいと思います。

Bypass password validation and create user anyway? [y/N]:
みたいにパスワード単純すぎるよ!みたいなこと言われるけど、無視してy入れていいです。
※ デプロイするときは、単純なパスワードは避ける

作成したユーザーでログインしてください。

モデルの名前である、
「POST」をクリック ⇨ 右上の「Postを追加」

押して、データを追加します。
そうしたら、以下のような登録フォーム出るのでデータを追加します。

スクリーンショット 2021-01-17 1.14.47.png

データを何個か追加してみてください。
DBにデータが追加されます。

ルーターに追加

最後に、ルートを追加します。

djnago-react-material/django-react-material/api/urls.py
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なので

http://127.0.0.1:8000/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のテーブル名違うけど
  • シリアライザーでデータを整える。
    • 今回は、単純な処理なので、処理はほぼしていない。
    • いらないカラムデータを削除(fieldsで指定したりする)、データを加工してJSONにするとかできる
    • 例えば、2021-01-17 12:00:00が見にくいから、2021年1月17日にしてJSONデータ作るとか
  • JSON形式でDjangoのAPIサーバーがデータを送信

少し長くなりましたが、これでできました。
URLにアクセスすると、

http://127.0.0.1:8000/api/posts

以下のように先ほど管理画面で登録したデータを取得できているのがわかります。

スクリーンショット 2021-01-17 1.48.10.png

Postmanで取得してみる

インストールしてない人はここから

https://www.postman.com/downloads/

APIを叩く(APIサーバーからデータもらう)ときによく使われるツールです。
先ほど確認できたので、大丈夫ですが、一応体験しましょう。

今回はGetで取得しますね。

手順

create request ⇨ URL入れる ⇨ Send

スクリーンショット 2021-01-17 1.59.07.png

認証のトークンをつけてAPIを叩いたり、
POSTデータを送信することもできるなどなど便利ツールです。
(今回はあまり使う意味なかったけど、WEBアプリ開発するなら入れておきましょう。使います。)

これだけだと、Reactで読み込めない

一見良さそうなんですけど、セキュリティとかの関係で今のままだと、
ReactではAPIを叩いてもデータを取得できません。
必要なものをインストールして、設定をします。

$ pipenv install django-cors-headers

設定が必要なので、以下を追加します。

settings.py
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ですので注意。

一応ちゃんと確認したい方は、リポジトリを見てください

https://github.com/adamchainz/django-cors-headers

Djangoはこれで完成です!🎉

ReactからDjangoのAPIサーバーにアクセス

※ こちらは前回作ったReactの続きです。

こちらはそれほどやることはなくて、URLを変更すれば良いだけです。

material-react/src/components/Content.js
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.jsconst { userId, id, title, body, avatarUrl, imageUrl } = props;と書いてあって、ここにデータが渡ります。

userIdは今回作っていませんが、もともと使っていなかったので表示には問題ないです。
(※ 消してもよかったですね…)

Reactサーバー起動

Reactを開発したディレクトリにて、サーバーを起動して、

$ npm start

URLにアクセスすると、

http://127.0.0.1:3000

うまくいけば、表示されます。

スクリーンショット 2021-01-17 2.32.50.png

Djangoの管理画面でデータを登録したら増えますので試してください。

APIで個別記事のデータ取得

次は、「詳細をみる」ボタンで表示される個別の詳細記事です。
実は、ModelViewSetを使うと一通りの機能を作ってくれているので、すでに完成しています。

http://localhost:8000/api/posts/1

とブラウザのURLのところに入れれば、データが表示されます。
スクリーンショット 2021-01-18 0.17.07.png

ついでに、コード書いてないですが、削除、変更もすでに実装されています。
DELETE、PUTのボタンありますよね。この画面のボタンを押しても、編集できますし、

Postmanで、HTTPの通信を使って、
消したり、変更したりを、所定の形式に従って送ってやれば実行されるAPIが完成してるんですね。

まあ、今のうちは、ModelViewSet使うと簡単にCRUD作れるんだねー
くらいで良いと思います。

Reactからこの個別記事詳細データを取得

前回の
[【初心者】React #3 ルーティング・ページ遷移 react-router-dom]
ですでにボタンから個別の記事に飛べるようにもなっていますので
API叩くためのURLを変えるだけでOK

material-react/src/components/PostContent.js
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です。

スクリーンショット 2021-01-18 2.29.29.png

一覧表示の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の値を以下のように貼り付け。

.env
SECRET_KEY=1234567890asdfghjklwertyzx
DEBUG=True

.envから読み込む記述と、
SECRET_KEY, DEBUGos.getenv('ここに.envに書いた名前書く')にする。

backend/settings.py
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選べば、
こんな感じの記述はすでに書かれていると思うのでその場合は不要です。

.gitignore
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

.gitignoreに追加すれば、変更を追跡しなくなるので、
うっかり後悔すると問題になる情報をgithubに公開してしまった!
ということはなくなります。

今回はDjangoのSECRET_KEYで、テストアプリなので公開しても特に問題はないと思います。
ただAPIキー、特にAWS関係の情報を晒したら、悪用されて多額の請求来ます!
隠したいファイルはあるけど、プロジェクトはgithubに公開しないといけないときには使いましょう。

:pushpin: 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サーバー繋ぐ ← ココ
34
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?