얼마 전 만든 PNU Quiz App.
실제 배포 환경에서 기존 방법에 어마 무시한 문제가 있어... 기능을 아예 새롭게 작성했다.
처음부터 이게 맞는 방향이었을 것 같은데... 괜히 쉬운 길을 택하려다 낭패를 봤다.
어쨌든 이렇게 작성한 코드를 리뷰해볼 예정!
1. 기존 방법 수정하기.
기존에는 유저가 각 보기를 클릭하고, 다음 버튼을 누르면,
해당 버튼의 value(보기의 내용)를 url에 담아 전달해주는 방법을 사용했다.
즉 어딘가에 저장되는 것도, 실제 선택이 제출되는 것도 아니었다!
(그냥 url에 담긴 value를 받아와 view에서 해당 value를 list안에 넣어주기만 했다)
이렇게 작성하고 나니...
유저의 정답이 담긴 list는 각 응답을 저장할 때, 그리고 점수를 매길 때 사용돼야 한다.
물론 이 둘은 각기 다른 함수를 통해 작동한다. 따라서 list는... view의 최상위에 전역으로 설정되어야 했다!
이렇게 배포를 하니... 세상에나, 서로 다른 유저가 한 view의 list를 공유하는게 아닌가!(사실 당연한 것)
즉 A가 체크한 정답이 다른 접속 환경의 B에게도 영향을 미치고 말았다.
이래서는 퀴즈라고 할 수가 없다!!! 따라서 해당 내용을 전면 수정.
2. Form을 통해 제출하기
그럼 어떻게 해야 하는가!
가장 직관적이면서도 정석인 방법... form의 submit을 이용하기로 했다.
즉 사용자가 퀴즈를 시작할 때마다 새로운 모델 object들을 생성하고,
이용자가 클릭해 제출한 값을 각 object안에 넣은 후,
결과 페이지에서 이용자가 제출한 값들과 정답을 비교해 점수를 매기는 것!
3. model 수정
models.py
총 3개의 모델을 만들었다.
제일 먼저 진짜 정답들이 담겨있는 Answer 모델(얘는 맨 마지막 체점시 사용된다).
다음은 이용자에게 띄워줄 질문과 보기들이 담긴 Question 모델.
마지막으로 이용자의 제출한 응답을 저장할 PnuUser모델(말만 user지 django의 user와는 아무런 관련이 없다).
즉 이용자가 퀴즈를 시작하면 자동적으로 새로운 PnuUser 모델이 하나 생성되고,
이용자가 퀴즈를 풀 때마다 제출한 답이 PnuUser의 answer이라는 필드 안에 저장되고,
퀴즈 종료 시 PnuUser의 answer이라는 필드에 담긴 답과 Answer이라는 모델에 담긴 정답(ans필드)을 비교!
4. view 작성
views.py
총 3개의 함수가 사용된다.
첫 페이지와 PnuUser생성을 담당할 home.
html상에 Question들을 띄워주고, 이용자의 응답을 저장하며, 정답과 비교해 점수를 매겨주는 quiz.
결과 화면을 띄워주고 전체 유저의 평균 점수를 구하는 result.
1) home
제일 먼저 home.
첫 화면인 home.html을 띄워주고, GET요청 시(문제 풀기 클릭 시) PnuUser를 생성한다.
이때 PnuUser의 name은 이용자가 input상에 기입한 이름.
아무것도 적지 않았을 시 그냥 "익명"이라는 이름으로 PnuUser가 생성된다.
save를 완료한 후 quiz함수로 redirect!
2) quiz
각 Question들을 template상에 띄워주는 quiz함수.
여기서 정말 획기적인 방법이 등장한다.
우리가 원하는 건? 한 페이지 당 하나의 Question을 띄워주는 것!
그런데 평소 하던 것처럼 Question.objects.all()을 context에 담아 보내주면...
for문을 돌며 모든 Question들이 template상에 띄워지게 된다!
그렇기 때문에... Question 중 id가 num인 녀석만을 가져와 template상에 띄워준다!
그리고 요 num는 이용자가 POST 요청을 보낼 때마다, 즉 한 문제를 풀 때마다 하나씩 늘어난다.
즉 각 페이지 별로 n번 째 Question 하나만 template상에 존재하는 것! 와우!
요 녀석은? 정답을 체점하는 코드!
이게 당최 무슨 소리??? 이를 알기 위해서는 admin페이지에 접속해야 한다.
우리가 생성한 model은 3개!
Answer에는 진짜 정답이 담겨 있고, PnuUser에는 이용자가 제출한 답이 담겨있다!
아하! 즉 user.answer = user.answer + request.POST['answer'] 를 통해
PnuUser의 answer필드에 request.POST['answer'] (얘는 이용자가 제출한 답) 를 넣어주는 것!
request.POST['answer']가 제출될 때마다 정답이 담긴 문자열과 비교해 num-2번째와 같으면 1점 더하기!
3) result
제일 별 기능이 없는 함수!
for문과 if문은 각각 유저 전체 점수의 평균과 에러 페이지를 위해 만들었는데...
사실 없어도 무관하다! 요는 result.html을 띄우는 것!
5. templates 작성
home.html
제일 첫 화면인 home.html!
이 부분을 클릭하면 아까 전 home 함수가 실행되며 PnuUser라는 모델이 생성된다.
quiz.html
쨔잔. Question 모델 안에 있는 option 1~4를 각각 form에 담아 보내준다!
hidden으로 숨겨둔 녀석들은 각각 문제 번호와 답 저장을 위해 숫자 형태를 보내주는 것!
이용자가 봐야하는 값은 {{quiz.option1~4}}이므로 나머지는 hidden으로 숨겼다.
result.html
각 이용자의 점수, 즉 {{user.score}}에 따라 다른 콘텐츠를 보여줘야 한다.
이를 위해 html 템플릿의 if문을 사용, score의 범위에 따라 다른 요소를 넣어줬다.
6. urls 작성
urls.py
url 작성. 별다른 건 없다!
사실 기존에 알고 있는 지식들 만으로도 충분히 작성이 가능했다..!
하지만 괜히 다른 걸 따라한다고 이상한 걸 참고하는 바람에... 애먼 시간을 날리고 말았다.
역시 자신이 완전히 이해할 수 있는, 근거가 있는 코드를 작성해야 한다.
어쨌든, 이렇게 작성하고 나면 기능적인 부분은 구현이 완료!
하지만 html과 css로만 이뤄진 웹페이지는... 영 심심하다.
여기서 js가 출동한다.
'source-code > Django' 카테고리의 다른 글
debug-tool-bar 이용하기 (0) | 2021.02.09 |
---|---|
PNU Quiz App _ django로 퀴즈 구현하기3 (1) | 2021.02.01 |
Django REST Framework _ 인증 기능 구현하기2 (0) | 2021.01.29 |
Django REST Framework _ 인증 기능 구현하기 (0) | 2021.01.25 |
Django REST Framework _ Mixin 사용하기 (0) | 2021.01.23 |