티스토리 뷰
통계페이지 만들기
내겐 강의평가 데이터가 있다.
강의평가 데이터로 통계페이지를 만들어볼까 한다.
원하는 건, 항목별 가장 높은 점수를 받은 과목이나 교수를 표에 보여주는 것이다.
딱히 난이도가 어려운 건 없다.
데이터를 디테일하게 만지는 데에 시간이 좀 오래 걸릴 뿐이다.
개요
1. 항목별 평균 구하기
2. 순위 매겨서 Rank model에 저장
3. html 작성
4. ajax 이용하여 항목별 Rank 출력
1. 항목별 평균 구하기
Course 아래 각 강의평가가 Response라는 이름으로 foreignkey가 붙어있다. (Response -> Course)
항목은 Question이다, 즉 여러 질문에 대한 5점 척도 평가들이 Response에 들어있다. (Question -> Response)
Question에 대한 답은 Answer에 저장되어 있다.
그러므로 Question에 Answer가 달려있다. (Answer -> Question & Answer -> Response)
Course에서 Question의 평균을 구해야 하므로, Response를 거쳐야한다.
Response가 3개 이상인 Course만 통계에 포함시킬 것이므로, 타겟 course는
from django.db.models import Count
from .models import Course, Question, Response
courses = Course.objects.annotate(num_resp=Count('response')).filter(num_resp__gte=3)
annotate는 queryset에서 변수를 설정하는 것이다.
위에선 response의 개수는 num_resp로 정의하고, 그게 3 이상인 course만 빼냈다.
참고한 stackoverflow.
비슷한 걸로는 aggregate가 있는데, 잘 알면 유용하게 쓰일 것 같다.
aggregate는 계산한 값이 바로 나오는데, 이걸로도 잘 조합하면 원하는 걸 구할 수는 있을 것 같다.
다만, 나는 한 단계를 더 거쳐야 하고 question에 따라 다른 값이 나와서 annotate를 사용했다.
참고로 3개 이상이 아니라 1개 이상이면 __isnull을 사용할 수도 있다.
courses = Course.objects.annotate(num_resp=Count('response')).filter(num_resp__isnull=False)
다만 이건 결과값이 다를 수 있으므로 주의한다.
course가 중복되기 때문이다.
sql로 바꾸면 쿼리가 좀 다른 것 같다.
여튼 그냥 gte=1 쓰자.
그 후 question q의 답인 answer의 값을 평균내야 한다.
여기서 좀 헷갈리는데, courses에 각 response의 특정 question에서 answer들의 평균을 내야한다.
import numpy as np
for course in courses:
resp_set = course.response_set.all()
np.mean(list(map(lambda x: int(x.answer_set.get(question=question).text), resp_set)))
복잡하다.
내 모델이 복잡하다.
2. 순위 매겨서 Rank model에 저장
Rank model은 항목(question)만 있으면 된다.
from django.db import models
class Rank(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
rank_str = models.TextField()
create_time = models.DateTimeField('time created', auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
question에 대해 순위들이 rank_str에 json.dumps로 변환되어 저장된다.
list가 dumps로 씌워졌다.
pickle의 dumps도 좋지만, 내가 admin에서 쉽게 바꾸기 위해 그냥 json을 이용했다. (pickle은 binary로 저장해서 사람이 읽을 수 없다)
(pickle도 admin에서 deserialize 해서 볼 수도 있지만 귀찮)
여기서 get_or_create를 썼는데, queryset를 get할 때, 있으면 있는 걸 쓰고, 없으면 만드는 거다.
음... 딱히 중요하지 않으니 넘어가자
3. html 작성
디자인은 센스가 필요하다.
나는 그냥 bootstrap에 table을 가져다 썼다.
<table class="table table-condensed">
...
</table>
그 위에 네비게이션 바를 넣어서, Question를 누르면 그에 맞는 Rank가 뜨도록 만들었다.
네비게이션 바도 부트스트랩에서 썼다.
4. ajax 이용하여 항목별 Rank 출력
요게 귀찮지만 요샌 필수적인 것이다.
이전에 새로고침 없게 데이터를 불러오는 걸 쓴 적이 있다.
똑같다.
네비게이션 바를 클릭하면 django view에 데이터를 요청하고, html 형식으로 데이터를 다시 전송해주면 javascript가 그걸 table에 적용해주는 식이다.
...
<ul class="nav nav-tabs">
{% for q in question %}
<li role="presentation">
<a class="nav_tab_elem" question={{ q.id }}>
{{ q.ask }}
</a>
</li>
{% endfor %}
</ul>
<table id="table">
...
</table>
...
<script type="text/javascript">
$(".nav_tab_elem").click(function(){
var question = $(this).attr('question')
$.ajax({
type: "POST", // 데이터를 전송하는 방법을 지정
url: "{% url 'app_name' %}", // 통신할 url을 지정
data: {"question": question,'csrfmiddlewaretoken': '{{ csrf_token }}'}, // 서버로 데이터 전송시 옵션
dataType: "text", // 서버측에서 전송한 데이터를 어떤 형식의 데이터로서 해석할 것인가를 지정, 없으면 알아서 판단
// 서버측에서 전송한 Response 데이터 형식
success: function(response){
$("#table").html(response);
}
}
});
});
</script>
nav_tab_elem이란 class를 누르면 (네비게이션 바) question이란 attribute(내가 넣어줌)가 POST 형식으로 app_name url로 넘어간다.
data에 저장된 question이랑 같이.
그럼 그걸 django view가 url을 거쳐서 받겠지? (자세한 설정은 이전 글 참고)
그런 다음에 view에서 정보(response)가 오면 dataType으로 인식(parse)하고 nav_tab의 html을 response로 변경한다.
def load_stat(request):
question = request.POST.get('question')
...
return render(request, 'stat_table.html', context)
question 처럼 받으면 되고, return 처럼 보내주면 된다.
'stat_table.html'이 html에서 response가 된다.
table을 id로 가진 요소가 response로 바뀌니까, stat_table.html에는 <table>...</.table>이 들어가면 된다.
주의할 점은, stat_table.html에 한글이 있으면 unicode decode error가 난다.
고칠 순 있는데, 난 귀찮아서 걍 다 영어로 바꿈.
그리고 자바스크립트에서 dataType이 text가 아니라 json이면 parse error가 난다.
json으로 보낼 땐 json, 아니면 text라고 하자.
참고로 디버깅할 때 유용한 팁이다
ajax 에러는 여기에 정리되어 있다.
html, javascript 디버깅은 웹 클라이언트가 잘 해준다.
난 개발서버에서 파이어폭스를 사용하므로 파이어폭스 개발자 도구를 사용했다.
break point를 만들고, 콘솔에서 console.log(...)로 출력할 수 있다.
에러 내용도 볼 수 있으니 유용.
끝.
너무 간단히 썼다.
'gistalk 개발' 카테고리의 다른 글
flutter - 1. 설치 (0) | 2020.07.27 |
---|---|
python 3.8 & Django 3.0 설치 (0) | 2020.03.13 |
[Django] forms와 views에서 invalid data error 출력하기 (0) | 2019.04.21 |
Django tas app 추가 6 : template tags & filters (0) | 2018.07.02 |
crawling하기 (0) | 2018.03.19 |
- Total
- Today
- Yesterday
- 아이템기반
- Supervised Learning #KoNLPy #Keras #NLP #자연어처리 #글 분류 #LSTM
- IBCF
- Python
- KAKAO
- memory-based
- windows subsystem for lunux
- 메모리기반
- queryset
- python3.8
- django mysql database sqlite
- MBCF
- n core setting
- pytorch
- gensim
- pythonpython
- 협업필터링
- javascrip
- MachineLearning #KMenas #KoNLPy #Word2Vec #AI #ML #인공지능 #Unsupervised #Clustering #Classification
- WSL2
- django3
- django
- 서버환경
- buffalo
- matrix factorization
- matrix market
- ifkakao
- item-based
- 추천
- Collaborative Filtering
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |