#はじめに
本記事へのアクセスありがとうございます。
投稿主はプログラミング初心者であり、この方法が**「最適解」**かは分かりません。
今度お仕事させて頂く実務でフロントにNuxt、バックエンドにDjangoを用いるので、全体の流れを少しでも把握するために本記事を作成しました。
同様な記事は環境構築までは確認できたのですが、せっかくならCRUD処理まで実装しようと思います。
*今回のNuxtの設定はSPAで行っていきます。時間があったらSSRバージョンも執筆します。
*DBはMySQLを使用します。
#この記事から得られるものは?
・Dockerを用いたNuxtとDjangoの環境構築
・上記の環境でAxiosでCRUD実装(get,post,put,delete 全て扱っている記事は少ない)
#さっそくスタート
Dockerを用いた環境構築はこちらの記事を参考にさせて頂きました。
環境構築完了イメージです。
##ディレクトリ構造
.
├─django
│ ├─manage.py
│ ├─qiitaexample
│ │ ├─settings.py
│ │ ├─urls.py
│ │ ├─wsgi.py
│ │ └─__init__.py
│ └─myapp
│ ├─migrations
│ ├─admin.py
│ ├─apps.py
│ ├─models.py
│ ├─renderers.py
│ ├─serializers.py
│ ├─tests.py
│ ├─urls.py
│ ├─views.py
│ └─__init__.py
│
├─docker-compose.yml
│
├─dockerfiles
│ ├─django_docker
│ │ ├─dockerfile
│ │ └─requirements.txt
│ └─nuxt_docker
│ └─dockerfile
│
├─mysql
│ └─conf.d
│
└─nuxt
└─front
└─以下略
##初期段階で必要なファイル内容
###docker-compose.yml
version: '3'
services:
db:
image: mysql:latest
restart: always
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: test
MYSQL_USER: test
MYSQL_DATABASE: test
MYSQL_PASSWORD: test
ports:
- 3306:3306
expose:
- 3306
volumes:
- mysqldata:/var/lib/mysql
- ./mysql/conf.d:/etc/mysql/conf.d
command: --default-authentication-plugin=mysql_native_password
web:
container_name: django
build: ./dockerfiles/django_docker
command:
python3 manage.py runserver 0.0.0.0:8000
volumes:
- ./django:/code
ports:
- "8000:8000"
depends_on:
- db
front:
container_name: nuxt
build: ./dockerfiles/nuxt_docker
tty: true
volumes:
- ./nuxt:/code
ports:
- "3000:3000"
volumes:
mysqldata:
###dockerfiles/nuxt_doceker/dockerfile
FROM node:latest
RUN mkdir -p /code
ENV NODE_ENV=development
RUN yarn install
RUN yarn add @nuxtjs/axios
WORKDIR /code
EXPOSE 3000
###dockerfiles/django_doceker/dockerfile
FROM python:3.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
COPY . /code/
###dockerfiles/django_doceker/requriements.txt
Django
djangorestframework
django-webpack-loader
django-cors-headers
mysqlclient
##Djangoの設定
###プロジェクトの作成
docker-composeでdbコンテナを立ち上げSqliteからMySQLの設定へと変更していきます。
> docker-compose up -d db
次にdocker-composeでコンテナを立ち上げます。初回なのでbuildも行っていきます。
> docker-compose up -d --build
Djangoのプロジェクトを作ります。(プロジェクト名は任意です)
> docker-compose run web django-admin.py startproject qiitaexample .
続いて、setting.pyを編集していきます。
#<DATABASESの'default'内を書き換える>
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'test',
'PASSWORD': 'test',
'HOST': 'db',
'PORT': '3306',
}
}
DATABASES変更後にDBのマイグレーションを行います。
> docker-compose run web ./manage.py migrate
続いてsuperuserを作成します。
> docker-compose run web ./manage.py createsuperuser --username admin --email admin@localhost
Password: #パスワードを聞かれるので入力
Password (again): #再度入力
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common. #パスワードが短いと警告が出る
Bypass password validation and create user anyway? [y/N]: y #yを入力
Superuser created successfully.
docker-compose up -d コマンドコンテナを全て立ち上げ、正常に動作しているか挙動を確かめます。
> docker-compose up -d
> docker ps
#3つのコンテナが動作しているはずです
・コンテナその1
・コンテナその2
・コンテナその3
django開発用サーバはポート8000で待ち受けているので、
http://localhost:8000/admin にアクセスしてみます。
表示された画面でUsername(ここではadmin)とpasswordを入力します。
すると、GroupsとUsersという2つの項目が表示されます。
###アプリの作成
さて、次はアプリを作成していきます。(ここではmyappという名前で作成します)
> docker-compose run web ./manage.py startapp myapp
setting.pyにmyappをを追記して使用できるようにします。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp', #追加
]
models.pyにモデルを追記していきます。
ここではStudentというモデルを作成します。
models.pyを追記後、マイグレーションをすることでMySQL上にテーブルが作成されます。
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=100)
course = models.CharField(max_length=100)
rating = models.IntegerField()
def __str__(self):
return self.name
class Meta:
ordering = ['name']
下記でマイグレーションを行います。
アプリを追加した場合はmakemigrationsが必要です。
> docker-compose run web ./manage.py makemigrations
> docker-compose run web ./manage.py migrate
admin.pyに下記を追記することで、管理画面から作成したモデルを確認できます。
from django.contrib import admin
from .models import Student
admin.site.register(Student)
再び http://localhost:8000/admin/ に接続するとMYAPPとStudentが増えていることが確認できます。
GUI操作で適当にStudentを登録し、MySQLのコンテナに入り確認してみます。
> docker exec -it mysql /bin/bash #MySQLコンテナに入る
> mysql -u test -p #MySQL起動
Enter password: #本記事の例だとtestでログイン可能
> use test;
> select * from myapp_student;
#確認できたら < shift + d > でコンテナから出る
##Django REST frameworkの構築
Djangoの準備ができたところで、次はDjango側にAPIを作っていきます。
まずはsetting.pyに追記していきます。(Nuxtとの通信の際に必要な処理も予め記載しておきます)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework', #追加
'corsheaders', #追加
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', #追加
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000',
]
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
'rest_framework'を追記することで、Django REST frameworkの機能を使用できるようになります。
続いて、serializer.pyとurls.py(myapp配下)を手動で新規作成します。
作成後にserializer.py、urls.py、views.pyに下記内容を追記します
from rest_framework.serializers import ModelSerializer
from .models import Student
class StudentSerializer(ModelSerializer):
class Meta:
model = Student
fields = ['id' , 'name' ,'course' ,'rating']
from django.shortcuts import render
from rest_framework.generics import ListAPIView, CreateAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView
from rest_framework.permissions import AllowAny
from .models import Student
from .serializers import StudentSerializer
class StudentsViewSet(ListAPIView):
model = Student
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (AllowAny, )
class StudentsDetailSet(RetrieveAPIView):
model = Student
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (AllowAny, )
class StudentsCreateSet(CreateAPIView):
model = Student
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (AllowAny, )
class StudentsUpdateSet(UpdateAPIView):
model = Student
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (AllowAny, )
class StudentsDeleteSet(DestroyAPIView):
model = Student
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (AllowAny, )
from django.urls import path
from .views import StudentsViewSet, StudentsCreateSet, StudentsUpdateSet,StudentsDetailSet,StudentsDeleteSet
urlpatterns = [
path('get_myapp/', StudentsViewSet.as_view()),
path('get_myapp/<int:pk>/', StudentsDetailSet.as_view()),
path('post_myapp/', StudentsCreateSet.as_view()),
path('put_myapp/<int:pk>/', StudentsUpdateSet.as_view()),
path('delete_myapp/<int:pk>/', StudentsDeleteSet.as_view()),
]
qiitaexample配下のurls.pyを編集し、myapp配下のurls.pyを有効にします。
from django.contrib import admin
from django.urls import path,include
from myapp import urls
urlpatterns = [
path('admin/', admin.site.urls),
path('api/',include(urls))
]
##Nuxt.jsの設定
始めにnuxt.jsのコンテナに入り、プロジェクトを作成します(プロジェクト名は任意です)。
yarn create nuxt-app frontを入力後の選択肢は基本全てデフォルト値を入れていますが、
今回はSPAを選択しています。
> docker exec -it nuxt /bin/bash
> yarn create nuxt-app front
確認のために開発用サーバを動かす前に、nuxt.config.jsに追記します。
docker上でnuxt.jsを動かす際は下記が必要です。
また、ここから編集していく際にホットリロードを有効にします。
docker上で開発するためには明示的に指定が必要です。
さらにaxiosの設定を追記していきます。
axiosはnode.jsで動くHTTPクライアントで、これを利用してnuxt.jsから先ほどのAPIのURLを叩きます。
前述のnuxtのdockerfileに記載してあるので、すでにコンテナにはインストール済です。
modulesに下記を追記、及びaxiosを追加します。
server: {
port: 3000,
host: '0.0.0.0',
},
watchers: {
webpack: {
poll: true
}
}
//~略~
modules: [
'@nuxtjs/axios',
],
axios: {
baseURL: "http://localhost:8000"
},
//~略~
これでdocker上でNuxt.jsを表示させることができます
> cd front
> yarn run dev
無事Nuxt.jsの初期画面が現れればひとまず成功です。
###AxiosでCRUD実装 Nuxt ⇆ Django
ここからは実際にNuxtとDjango間のデータの受け渡しについて記載していきます。
componentsの中にTestFormを新規作成します。
<template>
<div>
<div>
<form @submit.prevent="submitForm(student)">
<div class="from-group row">
<input
type="text"
class="form-control col-3 mx-2"
placeholder="Name"
v-model="student.name"
/>
<input
type="text"
class="form-control col-3 mx-2"
placeholder="Course"
v-model="student.course"
/>
<input
type="text"
class="form-control col-3 mx-2"
placeholder="Rating"
v-model="student.rating"
/>
<button class="btn btn-success">Submit</button>
</div>
</form>
</div>
<div>
<table class="tabel">
<thead>
<th>Name</th>
<th>Course</th>
<th>Rating</th>
</thead>
<tbody>
<tr
v-for="student in students"
:key="student.id"
@dblclick="$data.student = student"
>
<td>{{ student.name }}</td>
<td>{{ student.course }}</td>
<td>{{ student.rating }}</td>
<td><button @click="deleteStudent(student)">x</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
export default {
data() {
return {
student: {
name: "",
course: "",
rating: "",
},
students: [],
};
},
async created() {
await this.getStudents();
},
methods: {
submitForm(student) {
//新規にPOSTする場合はcrete , 既存にデータがある場合はputメソッドを利用するように条件分岐
if (this.student.id === undefined) {
this.createStudent();
} else {
this.editStudent(student);
}
},
//データを全権取得
async getStudents() {
const url = "/api/get_myapp/";
const response = await this.$axios.get(url);
this.students = response.data;
},
//データを新規登録
async createStudent() {
await this.getStudents();
const url = "/api/post_myapp/";
this.$axios.defaults.xsrfCookieName = "csrftoken";
this.$axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
await this.$axios.post(url, {
name: this.student.name,
course: this.student.course,
rating: this.student.rating,
});
await this.getStudents();
},
//データを編集
async editStudent(student) {
await this.getStudents();
const url = "/api/put_myapp/" + student.id + "/";
const modify = {
name: this.student.name,
course: this.student.course,
rating: this.student.rating,
};
await this.$axios.put(url, modify);
await this.getStudents();
this.student = {};
},
//データを削除
async deleteStudent(student) {
await this.getStudents();
const url = "/api/delete_myapp/" + student.id + "/";
const modify = {
name: this.student.name,
course: this.student.course,
rating: this.student.rating,
};
await this.$axios.delete(url)
await this.getStudents();
},
},
};
</script>
作成したTestFormを読みます。
不必要なら、template内の初期表示部分を削除してしまって構いません。
//追記
<div>
<TestForm />
</div>
--------------------
<script>
import TestForm from '~/components/TestForm.vue'
export default {
components:{
TestForm
}
}
</script>
これでAixosでCRUD処理のコードが完成です。
最後に全てのコンテナを立ち上げて、Nuxtのコンテナでyarn run devして確認してみましょう。
> docker-compose up -d
> docker exec -it nuxt /bin/bash
> cd front
> yarn run dev
#おわりに
お疲れ様でした。
以上でNuxt.js ⇆ Djangoのデータの連携が完成です。
個人的にはAxiosでputする時に以下のコードをurls.pyに書き忘れていて、ずっと404not foundで言われて少し苦戦しました。
解決してみれば確かに、詳細ページのurl設定を行っていないのでページが表示(一つ単位の情報を取得)できるはずもありませんでした。
path('get_myapp/<int:pk>/', StudentsDetailSet.as_view()),
**エラーコードを読みどこがいけないのか判断、予測して実装しなければ。**と改めて思いました。
余談ではありますが、DRFの理解の際に役に立ったリンクを紹介します。
Django REST framework カスタマイズ方法 - チュートリアルの補足
DRFのGeneric viewの使い方
少しでもみなさんのお役に立てたら嬉しいです。