概要
Vue.jsとDjango REST Frameworkを用いて、画像の登録及び表示する。
GitHubリンク
環境
-
macOS Monterey
-
Chip Apple M1 Max
-
Python 3.10.3
-
Django 4.1.4
-
Django REST Framework 3.14.0
-
vue-cli 5.0.1
-
Vue.js 3.2.13
手順
仮想環境構築
仮想環境を構築します。
% python -m venv venv
アクティベートします。
% source venv/bin/activate
Django環境構築
Django, djangorestframework, Pillowをインストールします。
(venv)% pip install Django==4.1.4 djangorestframework==3.14.0 Pillow==9.3.0
djangoプロジェクトを生成します。
(venv)% django-admin start project project .
開発サーバーを起動し、ブラウザでhttp://127.0.0.1:8000
を表示し、Djangoのデフォルト画面が表示されることを確認しましょう。
(venv)% python manage.py runserver
バックエンドを実装
djangoアプリを生成します。
(venv)% python manage.py startapp app
project/settings.pyを一部編集します。
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # 追加
'app' # 追加
]
...
# 以下を追記
MEDIA_URL = '/media/' # 画像ファイルを参照するためのURL
MEDIA_ROOT = BASE_DIR / "media" # 画像保存先ディレクトリ
# 信頼できる発信元リストに、Vueのオリジンを追加
CSRF_TRUSTED_ORIGINS = ['http://localhost:8080']
app/models.pyに、Imageモデルを定義します。
from django.db import models
class Image(models.Model):
image = models.ImageField(
verbose_name="画像",
blank=True,
null=True
)
class Meta:
db_table = "image"
app/views.pyにViewを定義します。
Vue.js側は後程実装します。
from rest_framework import viewsets, status
from rest_framework.response import Response
from .models import Image
from .serializers import ImageSerializer
class ImageViewSet(viewsets.ModelViewSet):
queryset = Image.objects.all()
serializer_class = ImageSerializer
app/serializers.pyを作成し、ImageSerializerを定義します。
from rest_framework import serializers
from .models import Image
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = "__all__"
project/urls.pyを編集
from django.contrib import admin
from django.conf import settings
from django.urls import path, include
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('app.urls')) # appのurls.pyを指定
]
if settings.DEBUG:
# 画像表示用
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
app/urls.pyを作成します。
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from app.views import ImageViewSet
# ImageViewSetを設定
router = DefaultRouter()
router.register(r'image', ImageViewSet)
urlpatterns = [
path('', include(router.urls)),
]
マイグレーションします。
% python manage.py makemigrations
% python manage.py migrate
開発サーバーを起動し、http://127.0.0.1:8000/api/v1/imageを開きます。
試しにChoose Fileに画像を設定し、POSTボタンで画像登録ができるか確認します。
Vue.jsプロジェクトを生成
本プロジェクトをVueプロジェクトを生成します。
% vue create frontend
Vue3を選択します。
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
開発サーバーを起動します。
% cd frontend
frontend% npm run serve
Vue.jsのデフォルト画面が表示されればOKです。
フロントエンドを実装
API実行のため、axiosをインストールします。
frontend% npm install axios
frontend/src/common/api.service.jsを作成し、以下を設定します。
import axios from "axios";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.withCredentials = true;
export { axios };
frontend/src/components/RegisterImage.vueを作成します。
<template>
<div>
<form @submit.prevent="onSubmit">
<div>画像</div>
<div>
<input
type="file"
name=""
id="img-upload"
ref="file"
multiple="multiple"
@change="uploadFile"
@click="
(e) => {
e.target.value = '';
}
"
/>
</div>
<button>登録</button>
</form>
<!-- プレビュー表示 -->
<img :src="imgUrl" />
</div>
</template>
<script>
import { axios } from "@/common/api.service.js";
export default {
data() {
return {
imgData: null,
imgUrl: null,
};
},
methods: {
uploadFile() {
this.imgData = this.$refs.file.files[0];
if (!this.imgData) {
return;
}
},
async onSubmit() {
const formData = new FormData();
formData.append("imageData", this.imgData);
console.log(this.imgData);
try {
const endpoint = "/api/v1/image/";
const response = await axios.post(endpoint, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
this.imgUrl = `http://localhost:8000${response.data}`;
alert("Success!");
} catch (error) {
console.log(error);
alert(error.response.data);
}
this.imgData = null;
},
},
};
</script>
※本来であれば、画像ファイルのみ受付できるよう実装すべきですが、今回は省略します。
frontend/vue.config.jsを編集します。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
publicPath: "/",
devServer: {
host: "localhost",
hot: "only",
proxy: {
"^/api": {
target: "http://localhost:8000",
changeOrigin: true,
},
},
},
})
frontend/src/App.vueを編集し、RegisterImageコンポーネントを表示するようにします。
<template>
<div>
<!-- <img alt="Vue logo" src="./assets/logo.png" /> -->
<!-- <HelloWorld msg="test" /> -->
<RegisterImage />
</div>
</template>
<script>
// import HelloWorld from "./components/HelloWorld.vue";
import RegisterImage from './components/RegisterImage.vue'
export default {
name: "App",
components: {
// HelloWorld,
RegisterImage
},
};
</script>
...
ここで、バックエンドのソースを一部編集します。
app/views.pyを編集し、フロントエンドからの登録リクエストにより、画像データを登録するよう修正します。
from rest_framework import viewsets, status
from rest_framework.response import Response
from .models import Image
from .serializers import ImageSerializer
class ImageViewSet(viewsets.ModelViewSet):
queryset = Image.objects.all()
serializer_class = ImageSerializer
# 以下を追加します
def create(self, request, *args, **kwargs):
# 画像登録処理
img_data = request.data['imageData']
if img_data is not None:
img = Image.objects.create(image=img_data)
return Response(img.image.url,
status=status.HTTP_200_OK)
return Response("Failed to register image.",
status=status.HTTP_400_BAD_REQUEST)
画像登録を実施
ここまでできたら、実際に登録処理を試してみましょう。
DjangoとVue.jsの開発用サーバーを両方起動します。
(venv)% python manage.py runserver
% cd frontend
% npm run server
ブラウザでhttp://localhost:8080
を開き、以下の画面が開くことを確認します。
アラートのOKを押下すると、アップロードしたプレビューが表示されることを確認します。
以上になります。
ありがとうございました。