Django REST APIをVue3からAxiosでアクセスするようなSPAサイトを開発する

環境構成(Django+Vue3+Vuetify+Axios)に沿った手順を順に説明します。


🌐 全体構成

vue_django/
│
├── project/              # Django プロジェクト
│   ├── settings.py
│   ├── urls.py
│   └── ...
├── app/                  # Django アプリ
│   ├── views.py
│   ├── urls.py
│   └── models.py
│
├── frontenv/             # Vue3 + Vuetify + Axios
│   ├── package.json
│   ├── src/
│   │   ├── main.js
│   │   ├── App.vue
│   │   └── views/
│   ├── public/
│   └── vue.config.js
│
├── static/               # Django 側静的ファイル出力先
└── templates/            # Django 側 HTML テンプレート出力先

最初にDjangoの環境構築

プロジェクト名をprojectとし、アプリケーション名をappとして構築します。

mkdir vue_django
cd vue_django
python -m venv ./venv
source venv/bin/activate
pip install django django-restframework
django-admin startproject project
chmod +x ./manage.py

Vue 3 + Vuetify 環境構築

vueの環境を構築:

npm install @vue/cli
cd vue_django/

vue create frontend
Vue CLI v5.0.9
? Please pick a preset: (Use arrow keys)
 Default ([Vue 3] babel, eslint) 
  Default ([Vue 2] babel, eslint) 
  Manually select features 

axiosとrouterの導入:

cd vue_django/frontend
vue add axios router

Vuetify 初期設定:

mkdir public
vue add vuetify
? Choose a preset: 
  Vuetify 2 - Configure Vue CLI (advanced) 
  Vuetify 2 - Vue CLI (recommended) 
  Vuetify 2 - Prototype (rapid development) 
  Vuetify 3 - Vite (preview) 
 Vuetify 3 - Vue CLI (preview) 

vue.config.jsを以下のように編集:

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  publicPath: "/",
  outputDir: "../static",
  assetsDir: "../static",
  indexPath: "../templates/index.html",
  transpileDependencies: true,
  pluginOptions: {
    vuetify: {
		}
  },
})

src/main.js を以下のように編集:

// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
loadFonts()

createApp(App).use(router)
  .use(router)
  .use(vuetify)
  .mount('#app')

Vuetify + Axios で Django REST API にアクセスする例

src/views/SampleView.vue を作成:

<template>
  <v-container>
    <v-card class="ma-5 pa-5">
      <v-card-title>Sample API Call</v-card-title>
      <v-card-text>
        <v-btn color="primary" @click="callApi">Call Django API</v-btn>
        <div class="mt-4">Response: {{ response }}</div>
      </v-card-text>
    </v-card>
  </v-container>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const response = ref('')

onMounted(async () => {
  try {
    const res = await axios.get('//localhost:8000/api/v1/sample/')
    response.value = res.data;
  } catch (err) {
    response.value = 'Error: ' + err.message
  }
});
</script>

src/router/index.js にルートを追加:

import { createRouter, createWebHistory } from 'vue-router'
import SampleView from '../views/SampleView.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: SampleView,
  },
]

export default createRouter({
  history: createWebHistory(),
  routes,
})

Django 側の調整

すでに REST Framework と SampleAPIView が動いているので、
Vue 側からアクセスできる状態です。
以下で確認可能:

# Django サーバ起動
./manage.py runserver 0.0.0.0:8000
# Vue 側開発サーバ起動
cd frontenv
npm run serve

Vue 側が http://localhost:8080、Django が http://localhost:8000
→ vue.config.js の proxy 設定により /api/ は Django 側へ中継されます。


SQLite3 を用いたモデルデータのAPI化

データベースへアクセスするための管理者用のアカウントを作成します。パスワードが短すぎたりすると注意がでてvalidationをbypassして良いか聞いてきますがここではyします。

cd ./vue_django
./manage.py makemigrations
./manage.py migrate
./manage.py createsuperuser
ユーザー名 (leave blank to use 'user'): admin
メールアドレス: <省略>
Password: admin
Password (again): admin
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

app/models.py 例:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published = models.DateField()

    def __str__(self):
        return self.title

app/serializers.py を追加:

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

app/views.py に追加:

from rest_framework import status, viewsets
from rest_framework.views import APIView
from rest_framework.response import Response

from django.views.generic.base import TemplateView
from .models import Book
from .serializers import BookSerializer

class IndexView(TemplateView):
    template_name = "index.html"

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    
class SampleAPIView(APIView):
    def get(self, request):
		    return Response("OK", status=status.HTTP_200_OK)

app/urls.py を更新:

from rest_framework import routers
from app.views import BookViewSet, IndexViewSet

router = routers.DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
    path('sample/', SampleAPIView.as_view(), name='sample'),
]
urlpatterns += router.urls

project/urls.pyを更新:

from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static

from app.views import IndexView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('app.urls')),
    re_path(r"^.*$", IndexView.as_view()),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

DBマイグレーション:

cd vue_django/
./manage.py makemigrations
./manage.py migrate

動作確認:

GET http://127.0.0.1:8000/api/v1/books/

Vue 側で axios 経由で呼び出せます。


✅ まとめ

要素技術状況
フロントVue3 + VuetifySPA構築OK
通信AxiosDjango REST Frameworkと通信
バックエンドDjango + DRF + SQLite3REST API提供
統合vue.config.js の proxy 設定 + Django IndexViewSPA統合OK

まずはSampleAPIViewでOKを得て表示されるところまでを作りました。次はコードの中にあったBookViewSet/BookSerializerの中身を表示させるようなものを作って見ようと思います。

http://localhost:8000/api/v1/books/

に、アクセスして以下の画面でタイトルと著者、発行年月日を何件か登録しておくとBookViewSetのコード作成時に出力が得られて動作確認がしやすいです。

あとは、Vue 側で CRUD 画面(一覧・追加・削除)を実装や、Django 側で認証(JWT / Session)対応などへ進めていってアプリケーションとして機能するものを作ってみようと思います。

タイトルとURLをコピーしました