Django REST FrameworkとVue.jsの環境構築

# 環境

- MacOS Monterey Version12.4
- Chip: Apple M1 Max

# 使用技術

- Python 3.10
- Django
- Django REST Framework
- Vue.js
- Vue CLI 5.0.1

# 全体のディレクトリ構成

```text
django-vue-env/
 ├app/
 ├frontend/ 
 ├project/
 ├static/     
 ├templates/　
 ├venv/
 ├db.sqlite3
 └manage.py 
```

# GitHubリンク

https://github.com/ryo-keima/django-vue-env


# 手順

## Python仮想環境を用意

プロジェクトを作成したいディレクトリを用意し、下記コマンドで仮想環境を用意する

```bash
% python -m venv venv
```

アクティベートする

```bash
(venv)% source venv/bin/activate
```

### Djangoプロジェクトを作成

pipをアップデートする

```
(venv)% pip install --upgrade pip
```

DjangoとDjango REST Frameworkをインストールする

```
(venv)% pip install Django==4.1.3 djangorestframework==3.14.0
```

djangoプロジェクトを作成する

```
(venv)% django-admin startproject project .
```

Djangoのデフォルト画面が表示されるか確認する

```
(venv)% python manage.py runserver
```

![Screen Shot 2022-11-12 at 10.44.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951524/b1104d01-8087-b7df-cf88-f72401811a49.png)

OK!

## Djangoアプリケーション作成

続いて、アプリケーションの作成を行います。

下記コマンドでappというアプリを作成します

```
(venv)% python manage.py startapp app
```

project/settings.pyのINSTALLED_APPSにrest_frameworkとappを追加します。

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'app'
]
```

app/views.pyを以下の内容に編集します。

```python
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

class SampleAPIView(APIView):

    def get(self, request):
        return Response("OK", status=status.HTTP_200_OK)
```

GETリクエストが来たら単に”OK”をするだけのviewです。

project/urls.pyの`urlpatterns`を編集します。

```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('app.urls')) # 追加
]
```

app/urls.pyを作成し、下記内容を記述します。

```python
from django.urls import path
from app.views import SampleAPIView

urlpatterns = [
    path("sample/", SampleAPIView.as_view(), name="sample"),
]
```

一度、APIが動作するか確認します。

開発サーバーを立ち上げ、ブラウザで[`http://127.0.0.1:8000/api/v1/sample/`](http://127.0.0.1:8000/api/v1/sample/)を開きます。

以下の画面が表示されればOKです。
![Screen Shot 2022-11-12 at 11.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951524/279c1736-63fc-488f-cb9b-0f3bc70cc892.png)


## Vue.jsプロジェクトを作成

Vue CLIをインストールします。

※ 公式HP
[https://cli.vuejs.org/guide/installation.htmlhttps://cli.vuejs.org/guide/installation.html](https://cli.vuejs.org/guide/installation.html)

```
% npm install -g @vue/cli
```

インストールされたことを確認します。

```
% vue --version
@vue/cli 5.0.1
```

frontendというVueプロジェクトを作成します。

```
% vue create frontend
```

今回は、Default ([Vue 3] babel, eslint) を選択します。

```
Vue CLI v5.0.1
┌─────────────────────────────────────────┐
│                                         │
│   New version available 5.0.1 → 5.0.8   │
│                                         │
└─────────────────────────────────────────┘

? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 3] babel, eslint) 
  Default ([Vue 2] babel, eslint) 
  Manually select features
```

以下のメッセージが表示されればOK。

```
Vue CLI v5.0.1
✨  Creating project in /Users/ryosukemaeda/Programming/Issues/django-vue-env/frontend.
⚙️  Installing CLI plugins. This might take a while...

added 848 packages in 12s
🚀  Invoking generators...
📦  Installing additional dependencies...

added 96 packages in 3s
⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project frontend.
👉  Get started with the following commands:

 $ cd frontend
 $ npm run serve
```

Vue.jsの開発サーバーを起動します。

まず、frontendディレクトリにチェンジディレクトリします。

```
% cd frontend
```

開発サーバーを起動します。

```
% npm run serve
```

以下のメッセージが表示されればOK。

```
DONE  Compiled successfully in 16996ms                 11:18:49 AM

  App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://172.20.10.9:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.
```

Vue.jsのデフォルト画面が表示されるか確認します。

ブラウザで`http://localhost:8080/`にアクセスします。

以下の画面が表示されればOKです。

![Screen Shot 2022-11-19 at 11.20.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951524/bef6990d-15ce-9e00-0dd7-f8ed135ba808.png)


## フロントエンドからAPIを実行する処理を実装

axiosをinstallします。

axiosとは、HTTP通信を簡単に行うことができる、JavaScriptのライブラリです。

frontendディレクトリ内で、以下のコマンドを実行します。

```jsx
% npm install axios
```

APIを実行する処理を実装します。

frontend/src/components/HelloWorld.vueの`<script>`タグの中を以下の様に編集します。

```jsx
<script>
import axios from "axios";

export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  data() {
    return {
      text: null,
    };
  },
  mounted() {
    axios
      .get("/api/v1/sample")
      .then((response) => (this.text = response.data))
      .catch((e) => console.log(e));
  },
};
</script>
```

APIの結果をUIに表示するようにします。

frontend/src/components/HelloWorld.vueの<template>タグの中を整理します。

```jsx
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <div>
      {{ text }}
    </div>
  </div>
</template>
```

frontend/vue.config.jsファイルを以下の内容に修正します。

```jsx
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    host: "localhost",
    hot: "only",
    proxy: {
      "^/api": {
        target: "http://localhost:8000",
        changeOrigin: true,
      },
    },
  },
})
```

## 開発環境の動作確認

Djangoの開発サーバーとVue.jsの開発サーバーを起動します。

```
(venv)% python manage.py runserver
```

```
frontend% npm run serve 
```

ブラウザで`http://localhost:8080/`にアクセスします。

以下の画面になっていればOKです。

![Screen Shot 2022-11-19 at 11.57.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951524/34bdf698-5b40-ad54-4e75-7716307ac27d.png)


## 本番環境用構築方法

DjangoでエントリーポイントとなるViewを作成します。

app/views.pyにIndexViewを作成します。

IndexViewは単に、index.htmlテンプレートを表示するだけのビューとします。

```python
from django.views.generic.base import TemplateView
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

class SampleAPIView(APIView):

    def get(self, request):
        return Response("OK", status=status.HTTP_200_OK)

class IndexView(TemplateView):

    template_name = "index.html"
```

IndexViewをproject/urls.pyに設定します。

```python
from django.contrib import admin
from django.urls import path, include, re_path

from app.views import IndexView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('app.urls')),
    re_path(r"^.*$", IndexView.as_view())
]
```

ここで重要なのは、`re_path(r"^.*$", IndexView.as_view())`を最後に記述することです。

これにより、admin/とapi/v1/以外のパスをIndexViewでキャッチできます。

続いて、index.htmlを作成したいのですが、これはVue.jsで作成したUIを使用したいので、その手順に移ります。

まず、django-vue-env/以下にstaticとtemplatesのディレクトリを作成します。

```
django-vue-env/
 ├app/
 ├frontend/ 
 ├project/
 ├static/     # 追加
 ├templates/　# 追加
 ├venv/
 ├db.sqlite3
 └manage.py 
```

frontend/vue.config.jsにビルド用の設定を追加します。

```jsx
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  publicPath: "/",
  outputDir: "../static",
  assetsDir:  "../static",
  indexPath: "../templates/index.html",
  transpileDependencies: true,
  devServer: {
    host: "localhost",
    hot: "only",
    proxy: {
      "^/api": {
        target: "http://localhost:8000",
        changeOrigin: true,
      },
    },
  },
})
```

※Vue CLIの公式ドキュメント

[https://cli.vuejs.org/config/](https://cli.vuejs.org/config/#vue-config-js)

上記ファイルの編集ができたら、ビルドを実行します。

```
frontend% npm run build 
```

templates/index.htmlが生成されており、staticディレクトリ以下にcss, jsファイルが生成されていればOK。

Djangoの開発サーバーを起動します。

```
(venv)% python manage.py runserver
```

ブラウザで`http://127.0.0.1:8000/`にアクセスします。

以下の画面になっていればOKです。

![Screen Shot 2022-11-30 at 20.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951524/721603ee-bccc-396c-c98e-68377730d328.png)


ありがとうございました。