본문 바로가기
source-code/Django

PNU Quiz App _ django로 퀴즈 구현하기

by mattew4483 2021. 1. 15.
728x90
반응형

해당 디자인

부산대학교 학생들을 위한 간단한 퀴즈 페이지를 구현해보기로 했다.

 

이를 위해 어떤 기능들이 필요할까?

1. 데이터베이스에 입력해둔 질문과 보기, 답을 하나씩 띄워준다.

2. 각 보기 중 정답을 클릭했을 때, 유저의 점수가 하나씩 올라간다.

3. 점수 범위에 따라 각기 다른 결과 페이지가 나온다.

 

흐음... 이렇게 적으니 어떻게 구현해야 할지 당최 감도 안 온다.

 

물론 수많은 개발자들이 퀴즈 기능을 구현할 수 있는 코드를 작성해뒀다. 대한민국 개발자 만세!

당연히 django를 이용한 것도 있다.

하지만 대부분이 프론트는 react, 백앤드는 django rest framework를 이용한 상태.

코드를 봐도 무슨 소리인지 깜깜...

 

youtu.be/q7MUD_3dJNc

그런데 오직 django를 이용해 이를 구현한 개발자가 있었다. 와우!

찬찬히 따라가 보도록 하자.


1. 기본 환경 세팅

늘 하던 것! projPNU라는 프로젝트와 Quiz라는 앱을 만들었다.

 

2. model 생성

models.py

문제와 보기, 그리고 답을 담을 모델을 만들었다.

question은 문제, option은 각 보기들, answer은 그 문제에 해당하는 정답이다.

img1은? 그림이 들어가는 문제가 있으므로 ImageField를 사용.

 

그런데 아직까지도 알 수가 없다.

한 모델 안에 문제와 보기와 정답이 다 있어도 되나? 정답 체크는 어떻게 하는 거지?? 맞춘 정답 개수는 어떻게 센담?

 

3. urls 작성

urls.py

프로젝트 파일의 url은 include를 통해 Quiz앱의 url로 향하도록!

 

urls.py

간단한 url. 이름 그대로 각각 첫 화면, 퀴즈 화면, 결과 화면을 띄워주는 url이다.

마지막 save_ans은? 이용자가 입력한 정답을 저장하는 함수인데... 이후 view에서 만나보자.

 

4. views & templates 작성

views.py

간단해서 좋다! 우선 home.html을 띄워준다.

 

1) Quiz 띄워주기

우선 우리가 만든 Quiz 모델을 html상에 띄워줘야 한다.

{% for i in model %} - {{i.quetion}} 을 사용하면 안 되나요? 되기는 되는데...

그러면 한 페이지에 for문으로 돌린 모든 object들이 나타날 테다.

우리가 원하는 건? 한 페이지당 한 문제! 정답을 제출하면 다음 문제로!

이를 위해? paginator을 이용하는 희한...하면서도 획기적인 방법을 사용한다.

 

views.py

우선 Question모델과 Paginator를 import 해주시고.

 

views.py

쨔잔. 요놈이 바로 quiz들을 띄워주는 함수.

요 녀석을 통해 한 페이지당 하나의 obj, 즉 하나의 모델만을 띄워줄 수 있게 된 것!

 

quiz.html

엄청난 길이! 와우!

우선 for문으로 view에서 받아온 question들을 돌면서 받아온다.

input type radio를 통해 우리가 설문조사에서 사용하는 보기 형식을 이용.

input type 중 유사한 checkbox라는 녀석도 있는데, 얘는 radio와 달리 중복 체크가 가능하다.

 

아무튼 {{i.option}}을 통해 우리가 모델에서 정해준 보기들을 하나씩 받아오는 중!

 

위에 {% if i.img %}를 쓴 이유는?

문제들 중 img가 있는 문제도 있고 없는 문제도 있는데... 이에 따라 화면 디자인이 달라진다!

따라서 if문을 통해 각기 다른 페이지 구성을 이용할 예정.

 

quiz.html

대망의 paginator부분.

사실 이전에 했던 거라 별 다를 것도 없다!

quetions.has_next, 즉 다음 페이지가 있을 경우 NEXT라는 버튼이(얘는 다음 페이지로 향하는 href를 걸어줬다),

다음 페이지가 없을 경우 답안지 제출이라는 버튼이(얘는 결과 페이지를 띄워주는 result함수를 작동시키도록!) 뜬다.

 

별 거 아니지만... 이 작업을 통해 한 페이지당 한 문제가, 다음 페이지에 넘어가면 다음 문제가 뜨도록 구현이 가능하다.

 

but 사실 이건 고급진 눈속임일 뿐... 

이러면 사용자가 값을 입력하지 않고 다음 문제로 향하는 것을 막을 수가 없다!(페이지가 넘어가는 것이므로)

 

2) result 띄워주기

어떻게 하면 이용자가 체크한 보기와 정답을 비교해, 맞는 응답의 개수를 알 수 있을까?

여러 가지 방법이 있겠지만...

여기서는 이용자가 제출한 보기를 각각 리스트에 담고,

이를 정답이 담긴 리스트와 순서대로 비교해, 

i번째가 같으면 점수가 0점에서 하나씩 증가하는 형태를 사용하려 한다.

 

여러 가지 방법들 중 이게 가장 별로인 듯싶다!

왜냐? 이용자가 제출을 2번 하는 등 리스트의 인자가 하나라도 초과되면 바로 out of range에러가 뜨기 때문...

그런데도 왜 이 방법을 택했냐고 물으면... 아직 아는 게 없기 때문. 흑흑.

 

script.js

대망의... js...

이용자가 next버튼과 제출 버튼을 누를 때마다 save_ans란 버튼 Id를 통해 onclick 이벤트를 작동시킨다.

이 onclick 이벤트는?(역시 save_ans로 이름 붙였다)

input에서 체크된 보기(name을 name으로 지정해줬었다)를 저장해 save_ans라는 url로 보내준다!

그럼 여기서의 save_ans은 또 뭔디? → view가 등장할 차례!

 

 

views.py

앞서 말한 것처럼 이용자가 입력한 보기가 담긴 list와 정답이 담긴 list를 비교해 맞춘 개수를 측정하려 한다.

이를 위해 views.py 제일 위해 전역 변수로!(어느 함수 안에 담긴 게 아니다) 각 list를 설정해준다.

정답이 담긴 list는 변하는 게 아니므로, for문을 통해 미리 받아와 주자.

 

views.py

(또) 대망의 view.

save_ans는 아까 js에서 url요청을 보냈을 시 작동되는데,

넘겨준 ans(이용자가 체크한 값이다)를 입력한 보기가 담긴 list에 하나씩 넣어준다!

이때 append를 사용했기 때문에 추가로 들어오는 값들은 맨 뒤로 보내진다. 즉 순서가 섞이지 않는다!

 

result는 결과를 보여주는 함수!

lst와 anslist의 i번째 인자들을 비교, 값이 같을 때마다 score가 하나씩 올라간다!

이를 통해 정답의 개수를 알 수 있을 테다! 와우!

 

result.html

마지막으로 html.

if문을 사용해 score의 구간 별로 다른 콘텐츠를 보여줄 수 있도록 했다.

view를 통해 넘겨줬기 때문에 {{score}}, {{lst}} 등을 사용해 점수나 체크한 값의 리스트를 보여줄 수 있다.

728x90
반응형

'source-code > Django' 카테고리의 다른 글

Django Rest Framework _ @api_view 사용하기  (0) 2021.01.21
Django REST Framework 맛보기  (0) 2021.01.19
Blogs App _ CSS 확장하기  (0) 2021.01.11
Blogs App _ 좋아요 기능  (0) 2021.01.10
Blogs App _ 동적 페이지 만들기  (0) 2021.01.08