[Django, Vue]Django + Vue CRUD 구현 2 - Front end

2021. 11. 26. 15:44 Python/Django

지금까지 Vue 에서 등록된 유저의 목록을 보여주는 Read 기능을 구현하였다. 조금씩 부분을 나눠 수정했던 일이 많았기에 

Create 기능을 만들기 전에 통합된 코드를 한번 보여주고 갈 것이다.

 

App.vue

// App.vue

<template>
  <div>
    <header></header>
    <!-- v-bind:하위컴포넌트 속성명="상위 컴포넌트 전달할 데이터명"  -->
    <content v-bind:propsdata="userList"></content> 
    <footer></footer>
  </div>
</template>

<script>
import axios from "axios";
import Header from "./components/Header.vue";
import Content from "./components/Content.vue";
import Footer from "./components/Footer.vue";

let url = "http://localhost:8000/user/";  // 장고 서버 주소

export default {
  data: () => {
    return {
      userList: [],
    };
  },
  components: {
    "header": Header,
    "content": Content,
    "footer": Footer
  },
  mounted() { // DOM 객체 생성 후 drf server 에서 데이터를 가져와 todoList 저장
    axios({
      method: "GET",
      url: url 
    })
      .then(response => {
        this.userList = response.data;
      })
      .catch(response => {
        console.log("Failed to get userList", response);
      });
  },
  methods: {  // CRUD 로직
    getUserList: function() {},
    updateUserList: function() {},
    deleteUserList: function() {}
  }
};
</script>

<style>
</style>

 

Vuetify 레이아웃 변경

Vuetify 는 12구획으로 나누어진 Grid system을 지원한다. 즉, 하나의 열(row)는 12개의 컬럼(column) 으로 구성된다는 뜻이다.

따라서 우리는 이것을 사용하여 layout을 변경해볼 것이다.

 

Grid system에서는 다음과 같은 세가지 컴포넌트가 존재한다. v-flex가 가장 하위 컴포넌트이다.

  • v-container : 중앙 중심의 페이지에 적용됨, 컨텐츠를 담을 컨테이너를 의미함
  • v-layout : 각 섹션을 분리하는데 사용됨, 단일 컨텐츠 항목인 v-flew를 포함하는 레이아웃을 정의함
  • v-flex : 레이아웃을 효과적으로 표현하기 위해 도입된 도구

Vuetify 12 Grid system

 

Content.vue layout 변경

<!-- Content.vue -->

<template>
    <div>
        <!-- 변경 -->
        <v-container fluid>
            <!-- 전체 너비를 사용 : fluid -->
            <v-layout column>
                <v-flex>
                    <h3 class="subject">user CRUD</h3>
                </v-flex>
                <v-flex column>
                    <v-row>
                        <v-col cols="4" md="4">
                            <!-- 합이 12 -> 전체화면 -->
                            <v-text-field v-model="data.usename" :counter="15" label="Username" required></v-text-field>
                        </v-col>
                        <v-col cols="4" md="4">
                            <v-text-field v-model="data.age" label="Age" required></v-text-field>
                        </v-col>
                        <v-col cols="4" md="4">
                            <v-text-field v-model="data.city" :counter="15" label="City" required></v-text-field>
                        </v-col>
                    </v-row>
                    <v-btn @click="sendForm" style="background: green">create</v-btn>
                    <v-btn @click="clearForm" style="background: red">clear</v-btn>
                </v-flex>
                <!-- 변경 -->

                <v-flex class="userList" column>
                    <v-card max-width="600" tile>
                        <v-list-item v-for="(data, index) in propsdata" v-bind:key="index">
                            <v-list-item-content>
                                <v-list-item-title>이름 : {{ data.username }}</v-list-item-title>
                                <v-list-item-subtitle>나이 : {{ data.age }}세, 거주지: {{ data.city }}</v-list-item-subtitle>
                            </v-list-item-content>
                        </v-list-item>
                    </v-card>
                </v-flex>
            </v-layout>
        </v-container>
    </div>
</template>

vuetify 가 지원하는 grid system 을 통해서 레이아웃을 변경하였다. v-model 이라는 것을 사용하여 코드를 수정하였는데
v-model 이 무엇인지에 대해 알아볼 것이다.

 

양방향 데이터 바인딩 v-model

v-model 을 이해하기 위해서는 먼저 v-model 속성이 v-bind와 v-on의 기능의 조합으로 동작한다는 것을 알아야 한다.

그렇다면 v-bind 와 v-on은 무엇일까?

  • v-bind : 뷰 인스턴스의 데이터 속성을 해당 HTML 요소에 연결할 때(바인딩) 사용함
  • v-on : 해당 HTML 요소의 이벤트를 뷰 인스턴스의 로직(메소드 포함)과 연결할 때 사용함

v-on & v-bind 사용 예시

<input v-bind:value="inputText" v-on:input="updateInput">
new Vue({
  data: {
    inputText: ''
  },
  methods: {
    updateInput: function(event) {
      var updatedText = event.target.value;
      this.inputText = updatedText;
    }
  }
})

위의 코드에서는 v-bind 와 v-on를 사용하였는데, v-model을 사용하면 조금 더 간략하게 만들 수 있다.

 

v-model 사용 예시

<input v-model="inputText">
new Vue({
  data: {
    inputText: ''
  }
})

이벤트가 발생 시 input 메소드를 실행하기 위해 사용했던 v-on, data속성과 바인딩 시 사용했던 v-bind를 한번에 사용하는 기능을 위해
v-model을 사용해 Vue의 data와 input을 양방향 바인딩 하도록 하였다. 동작은 같지만 이전에 비해 코드가 간략해진 것을 알 수 있다.

 

이제 다시 위의 Content.vue의 코드를 설명하면서 진행하겠다.

v-model="data.username" -> data의 username에 form에서 입력한 값을 바인딩(넣는다)한다는 의미이다.

@click="sendForm" -> create 버튼을 누를 시 sendForm 메소드를 실행해 백엔드 서버로 데이터를 전송한다는 의미이다.

즉, form에 값을 입력하면 Vue 인스턴스의 data에 입력한 값이 전달되고, create 버튼을 누르면 데이터가 백엔드(장고) 서버로
전송된다는 뜻이다.

 

Content.vue 추가

<!-- Content.vue -->

<script>
import axios from "axios";
let url = "http://localhost:8000/user/";

export default {
    data: () => {
        return {
            data: {
                username: "",
                age: "",
                city: "",
            },
        };
    },
    props: ["propsdata"],
    methods: {
        sendForm: function() {
            axios({
                method: "POST",
                url: url,
                data: this.data,
            })
                .then((response) => {
                    this.userList = response.data;
                })
                .catch((error) => {
                    console.log("Failed to get userList", error.response);
                });
        },
        clearForm: function() {
            (this.data.username = ""), (this.data.age = ""), (this.data.city = "");
        },
    },
};
</script>

Content.vue 파일의 script 부분에 해당 내용을 추가하여 주자. 이전에 설치했던 axios를 통해서 데이터를 주고 받고, sendForm, clearForm 함수를 선언하여 create 버튼을 누를시 장고 백엔드 서버로 데이터를 Create 하고, clearForm 에서는 입력한 값을 지워주는
기능을 구현하였다. 

장고와 뷰 서버를 모두 동작시킨 다음 form에 값을 넣고 create 버튼을 누르면 백엔드 서버 DB에 값이 잘 저장되는 것을 확인할 수 있다.

하지만 새로고침을 하지 않을 경우 저장된 값을 vue에서 바로 볼 수 없게 되어있다. 이 부분을 다음 포스팅에서 수정할 것이다.

 

이번 포스팅에서는 Create 기능까지 구현하였다.
다음 포스팅에서는 새로고침 버튼을 누르지 않고도 데이터가 저장된 것을 확인할 수 있게 만드는 작업을 할 것이다.

 

출처 : https://leffept.tistory.com/292?category=950490