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
👉🏻깃허브 소스