Thank you for accessing this article. The poster is new to programming and I'm not sure if this method is ** "optimal" **.
I will use Nuxt for the front and Django for the back end in my next work, so I created this article to understand the whole flow as much as possible. I was able to confirm a similar article up to the environment construction, but I would like to implement CRUD processing as well.
・ Nuxt and Django environment construction using Docker -CRUD implementation with Axios in the above environment (get, post, put, delete, there are few articles dealing with all)
For environment construction using Docker, I referred to the article here. It is an image of environment construction completion.
.
├─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
└─Omitted below
docker-compose.yml
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
requriements.txt
Django
djangorestframework
django-webpack-loader
django-cors-headers
mysqlclient
Launch the db container with docker-compose and change from Sqlite to MySQL settings.
> docker-compose up -d db
Next, launch the container with docker-compose. Since this is the first time, we will also build.
> docker-compose up -d --build
Create a Django project. (Project name is arbitrary)
> docker-compose run web django-admin.py startproject qiitaexample .
Next, edit setting.py.
#<DATABASES'default'Rewrite inside>
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'test',
'PASSWORD': 'test',
'HOST': 'db',
'PORT': '3306',
}
}
DB migration will be performed after changing DATABASES.
> docker-compose run web ./manage.py migrate
Then create a superuser.
> docker-compose run web ./manage.py createsuperuser --username admin --email admin@localhost
Password: #You will be asked for a password, so enter it
Password (again): #Enter 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. #Warning if password is short
Bypass password validation and create user anyway? [y/N]: y #Enter y
Superuser created successfully.
Start all docker-compose up -d command containers and check the behavior to see if they are working properly.
> docker-compose up -d
> docker ps
#3 containers should be working
・ Container 1
・ Container 2
・ Container 3
The django development server is listening on port 8000, so Try accessing http: // localhost: 8000/admin. On the screen that appears, enter your Username (admin in this case) and password. Then, two items, Groups and Users, will be displayed.
Now, let's create an app. (Here, create it with the name myapp)
> docker-compose run web ./manage.py startapp myapp
Add myapp to setting.py so that it can be used.
./django/qiitaexample/setting.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp', #add to
]
I will add the model to models.py. Here, we will create a model called Student. After adding models.py, a table will be created on MySQL by migrating.
./django/myapp/models.py
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']
Migrate below. If you added an app, you need make migrations.
> docker-compose run web ./manage.py makemigrations
> docker-compose run web ./manage.py migrate
You can check the created model from the management screen by adding the following to admin.py.
./django/myapp/admin.py
from django.contrib import admin
from .models import Student
admin.site.register(Student)
If you connect to http: // localhost: 8000/admin/again, you can see that MYAPP and Student are increasing. Register the Student appropriately by GUI operation, enter the MySQL container and check it.
> docker exec -it mysql /bin/bash #Enter the MySQL container
> mysql -u test -p #Start MySQL
Enter password: #In the example of this article, you can log in with test
> use test;
> select * from myapp_student;
#If you can confirm< shift + d >Get out of the container with
Now that Django is ready, it's time to create an API on the Django side. First, add it to setting.py. (The processing required for communication with Nuxt is also described in advance)
./django/qiitaexample/setting.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
'rest_framework', #add to
'corsheaders', #add to
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', #add to
'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
By adding'rest_framework', you will be able to use the features of the Django REST framework. Next, manually create new serializer.py and urls.py (under myapp). After creating, add the following contents to serializer.py, urls.py, views.py
./django/myapp/serializers.py
from rest_framework.serializers import ModelSerializer
from .models import Student
class StudentSerializer(ModelSerializer):
class Meta:
model = Student
fields = ['id' , 'name' ,'course' ,'rating']
./django/myapp/views.py
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, )
./django/myapp/urls.py
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()),
]
Edit urls.py under qiitaexample and enable urls.py under myapp.
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))
]
First, go into the nuxt.js container and create a project (project name is arbitrary).
After entering yarn create nuxt-app front, all the choices are basically default values, This time I have selected SPA.
> docker exec -it nuxt /bin/bash
> yarn create nuxt-app front
Before running the development server for confirmation, add it to nuxt.config.js. The following is required to run nuxt.js on docker. Also, enable hot reload when editing from here. You need to specify it explicitly to develop on docker.
Furthermore, I will add the settings of axios. axios is an HTTP client that runs on node.js, and uses this to hit the URL of the API from nuxt.js. Since it is described in the dockerfile of nuxt mentioned above, it is already installed in the container. Add the following to modules and add axios.
./nuxt/front/nuxt.config.js
server: {
port: 3000,
host: '0.0.0.0',
},
watchers: {
webpack: {
poll: true
}
}
//~Abbreviation~
modules: [
'@nuxtjs/axios',
],
axios: {
baseURL: "http://localhost:8000"
},
//~Abbreviation~
Now you can see Nuxt.js on docker
> cd front
> yarn run dev
If the initial screen of Nuxt.js appears safely, it is a success for the time being.
From here, I will actually describe the data transfer between Nuxt and Django. Create a new TestForm in the components.
./nuxt/front/components/TestForm.vue
<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) {
//Crete for new POST,Conditional branch to use put method when there is existing data
if (this.student.id === undefined) {
this.createStudent();
} else {
this.editStudent(student);
}
},
//Get full rights to data
async getStudents() {
const url = "/api/get_myapp/";
const response = await this.$axios.get(url);
this.students = response.data;
},
//New data registration
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();
},
//Edit data
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 = {};
},
//Delete data
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>
Read the created TestForm. If you don't need it, you can delete the initial display part in the template.
./nuxt/front/pages/index.vue
//Postscript
<div>
<TestForm />
</div>
--------------------
<script>
import TestForm from '~/components/TestForm.vue'
export default {
components:{
TestForm
}
}
</script>
This completes the CRUD processing code in Aixos. Finally, let's launch all the containers and do yarn run dev in the Nuxt container to check.
> docker-compose up -d
> docker exex -it nuxt /bin/bash
> cd front
> yarn run dev
Thank you for your hard work. This completes the Nuxt.js ⇆ Django data linkage. Personally, I forgot to write the following code in urls.py when putting with Axios, and I was told 404 not found all the time and struggled a little. When I solved it, I couldn't see the page (get information for each unit) because I didn't set the url of the detail page.
path('get_myapp/<int:pk>/', StudentsDetailSet.as_view()),
** You have to read the error code to determine what is wrong, predict it, and implement it. I thought again **.
As an aside, here are some links that helped me understand DRF. How to customize the Django REST framework-Tutorial supplement How to use DRF generic view
I hope it helps you even a little.