Django #8-2 - Create, JSON 연동하기

Corner·2022년 4월 30일
0

django

목록 보기
13/14

Create

todo_index.html에 add_todo 함수를 수정 작업한다.

add_todo: function () {
    console.log("add_todo()...");
    if (this.name === '') {
        this.name = 'user'
    }
    if (this.todo === '') {
        return;
    }

    var vm = this;
    var postData = {
        name: this.name, todo: this.todo
    };
    axios.post('/api/todo/create/', postData).then(function (res) {
        console.log("post res", res);
        vm.todoList.push({id: res.data.id, name: res.data.name, todo: res.data.todo});
    }).catch(function (err) {
        console.log(err);
    })
    this.name = this.todo = '';
},

여기서 postData의 오브젝트 형식으로 name과 todo 값을 담고있는데, 이 this.name과 this.todo는

vue.js에서 data로 선언해둔 데이터로, html 폼에서 v-model 데이터로 양방향 바인딩이 되기 때문에

함수의 매개변수로 넣지 않아도 가능하다.

urls.py에 api url을 추가한다.

path('todo/create/', views.ApiTodoCV.as_view(), name='create') 

views.py

@method_decorator(csrf_exempt, name='dispatch')
class ApiTodoCV(BaseCreateView):
    model = Todo
    fields = '__all__' # 필수

    def form_valid(self, form):
        print("form_valid()", form)

    def form_invalid(self, form):
        print("form_invaild()", form)

독스에서 create - post 를 했을 떄 BaseCreateView가 아닌, 상위 createView를 보면 form_valid 와 form_invalid 메소드를 확인해보기 위해 프린트를 찍어 확인해본다.

form_invaild() 
<tr>
<th><label for="id_name">NAME:</label></th>
<td><input type="text" name="name" maxlength="5" id="id_name"></td>
</tr>

<tr>
<th><label for="id_todo">TODO:</label></th>
<td>
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="todo" maxlength="50" required id="id_todo">
</td>
</tr>

장고의 콘솔 에러를 확인해보면

name과 todo 데이터가 들어오지 않아 발생된 에러라고 생각된다.

개발자 도구에서 확인해보면

페이로드에서는 값을 잘 전달하고 있지만 500에러가 발생하는데

보통 500에러는 장고 (백단)에서 서버 통신 에러이기 떄문에

장고에서 처리하는 로직을 확인해 원인 분석을 해야한다.

get_form 메소드로 form을 만들었는데 그 form에서 에러가 있어서 form_invalid를 탄 것이기 때문에

get_form 메소드를 확인해보아야 한다.

get_form_kwargs 에서 'data' : self.request.Post

Django Docs 공식 문서에서 확인할 수 있는데

HttpRequest objects 에 관해 설명을 보면

HttpRequest.POST가 있는데

form이 아닌 경우에는 HttpRequest.body를 사용하라고 설명되어있다.

HttpRequest.body의 설명을 보면

바이트 스트링(byte string)으로 받고 있다.

장고에서는 폼 데이터 기능으로 받는게 아니라 axios로 데이터를 받고있기 때문에

HttpRequest.POST를 사용하는게 아니라, HttpRequest.body를 사용해야한다.

정말 그런지 확인하기 위해 다시 파이참으로 돌아와 def form_invalid 부분에

print("form_invaild()", self.request.POST)
print("form_invaild()", self.request.body.decode('utf8'))

해당 프린트를 찍어서 확인해보도록 한다. HttpRequest.body는 byte형 이기 때문에 decode를 한다.

확인해보니 self.request.body의 프린트가 잘 출력되는걸로 봐서

해당 기능을 이용해야 한다.

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['data'] = dict(self.request.body)
       

form_valid 메소드 위에 get_form_kwargs 메소드를 추가하는데,

self.request.body의 경우 dict 타입으로 형변환을 해주어야 한다.

dict(.....)로 감싸면 형변환이 되는지 확인해본다.

파이썬 콘솔을으로 확인해보면

str 형 타입과 dict 형 타입은 프린트로 찍었을 땐 구분이 안되기 때문에 유의한다.

한 가지 주의할 점은 json 형식의 키를 만들 땐 key값은 쌍따옴표 ("")로 감싸주어야 한다.

js = '{"a": 1}'
dict(js)
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 1; 2 is required

파이썬 콘솔에 json 형식으로 선언하고 dict 타입으로 변환해보았더니 오류가 뜬다.

이럴 땐 json.loads를 이용하는 것인데

import json
>>> json.loads(js)
{'a': 1}
>>> type(json.loads(js))
<class 'dict'>

이런식으로 형변환이 가능하다.

views.py

def get_form_kwargs(self):
    kwargs = super().get_form_kwargs()
    kwargs['data'] = json.loads(self.request.body)
    return kwargs

이런식으로 사용해서 테스트 해보면 오류는 그대로지만, 콘솔에는 프린트문이 잘 찍히게된다.

이로써 views.py에 ApiTodoCV 클래스 코드를 확인해보면

@method_decorator(csrf_exempt, name='dispatch')
class ApiTodoCV(BaseCreateView):
    model = Todo
    fields = '__all__' # 필수

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['data'] = json.loads(self.request.body)
        return kwargs

    def form_valid(self, form):
        print("form_valid()", form)
        self.object = form.save()
        newTodo = model_to_dict(self.object)
        print(f"newtodo: {newTodo}") # f 스트링 파이썬 3.6부터 도입된 문법
        return JsonResponse(data=newTodo, status=201)

    def form_invalid(self, form):
        print("form_invaild()", form)
        print("form_invaild()", self.request.POST)
        print("form_invaild()", self.request.body.decode('utf8'))
        return JsonResponse(data=form.errors, status=400) # 클라이언트 에러

이제 테스트를 해보고 마치도록 한다.

Todo에 내용을 적고 추가하면

콘솔에도 이제 정상적으로 Create가 되었음을 알 수 있다.


GitHub Source

👉🏻깃허브 소스

profile
Full-stack Engineer. email - corner3499@kakao.com,

0개의 댓글