django 특정 필드의 데이터 갯수로 정렬하기 (python dictionary 정렬)

파오리·2021년 3월 10일
0

아주 작은 기록

목록 보기
11/13

지난번에 했던 거를.. 완전 잘못 생각한 치명적 오류가 있어서 새로 알고리즘을 짰다. 새로 테이블 만들어서 foreign key로 연결할 필요도 없었다.진짜 멍청하기 짝이 없다
삽질기록..

내가 하려는 것: 검색필터를 통해 이미 한번 걸러진 Nac의 데이터 중에, user를 기준으로 데이터 갯수가 많은 것부터 순서대로 5개의 user를 정렬

지난 번에 했던대로 Accessor 테이블을 연결하면, Accessor에 저장되는 count는 지금까지의 접근 전체 count이므로 날짜나 시간으로 검색을 했을 경우에는 원하는 결과가 나오지 않는다.
예를 들어 3월 접근 순위를 보고 싶어서 2020-03을 검색하지만, 나오는 순위는 현재까지의 접근 전체를 기준으로 걸러진 것이라는 것.

진짜 너무 멍청해서 할 말이 없다....
왜 그 때는 그렇게 밖에 생각을 하지 못했는지 참 알 수 없다.

그래서 뚝딱 다시 짜봤다.

시나리오

일단, 간단히 이야기 하면 날짜나 시간으로 검색을 했을 때, 해당 날짜로 걸러진 데이터들 중에서 user갯수가 많은 순으로 정렬해서 상위 5개를 뽑는 거다.

정렬이라 하면 order_by를 떠올리게 되는데, user는 문자열이라 문자열을 order_by로 정렬하면 갯수가 아니라, 문자의 순서로 정렬이 된다.

그래서 따로 user별로 데이터의 갯수를 세야 한다.

1) 검색 쿼리로 해당 날짜에 해당하는 데이터들을 뽑기
2) 뽑은 데이터들에 존재하는 user목록을 중복없는 리스트로 만들기
3) 각각의 user에 해당하는 데이터들의 갯수를 세서 user와 매칭하기 (dictionary사용)
4) user에 매칭되는 갯수를 내림차순으로 정렬하기
5) 정렬된 dictionary에서 key값인 user의 맨 앞 5개 가져오기

해결

참고: python dictionary 정렬

# django views.py

from django.shortcuts import render, redirect
from .models import Nac
from django.db.models import Q
from django.db.models import Count

import operator


def nacSearch(request):
	search = request.GET.get('search', '') # 검색 쿼리
    
    if search:
    	nacList = Nac.objects.all().order_by('-id')
        nacList_search = nacList.filter(Q(time__icontains=search) | Q(user_id__name__icontains=search) |  
                                Q(ip__icontains=search) | Q(result__icontains=search) | Q(message__icontains=search))	# 검색 결과 데이터 필터링
        
        nac_access_rank = {}	# user별 데이터 갯수를 매칭하여 저장할 dictionary
        nacList_user = nacList_search.values_list('user_id__name', flat=True).distinct()	# 검색결과의 user 목록; 테이블 구조는 지난번과 같음.
        for user in nacList_user:
            nac_access_rank[user] = nacList_search.filter(user_id__name=user).count()	# user을 key로, 해당 user의 데이터 갯수를 value로 가짐
        nac_rank = sorted(nac_access_rank.items(), key=operator.itemgetter(1), reverse=True)	# value값을 기준으로 내림차순 정렬
		nac_rank = nac_rank[:5]		#앞 5개 데이터만 가져옴
        
        return render(request, 'nac_search.html', {'nac_rank':nac_rank})
    else:
        return redirect('/system/nac/')
            
...
<div class="summary__card">
  <h4 class="summary__card_info">
    🔍검색 결과 접근 top 5:
    </br>
    {% if nac_rank %}
      {% for rank in nac_rank %}
          {{forloop.counter}}위 <span class="search_result">{{rank.0}}</span><span>({{rank.1}}회)</span>
      {% endfor %}
    {% endif %}
  </h4>
 </div>

이렇게 하면

이렇게 2021-02로 검색했을 때, 해당 기간 안에 접근한 사람만 순위로 뽑아낼 수 있다.

성공~

profile
경험 == 배움

0개의 댓글