0. 서론
이제 거의 마무리가 되는 시점에서 스트리머 전적검색의 사용성 개선을 하려고합니다. 대표적으로 쉽게쉽게 다른 url로 넘어가는 버튼을 만들던가 스트리머 저장버튼을 만들던가 업데이트 버튼을 만들어서 비로그인 사용자라도 저장된 스트리머들의 티어를 업데이트(갱신)을 하거나 이런식의 기능을 추가하였습니다.
주소 : 깃허브
1) 스트리머 정보 저장
@csrf_exempt
def save_streamer_tier(request):
if not request.user.is_superuser:
return HttpResponseForbidden("이 작업은 관리자만 수행할 수 있습니다.")
if request.method == 'POST':
# 세션 데이터 확인
game_name = request.session.get('summoner_name')
tag_line = request.session.get('tag_line')
tier_info = request.session.get('tier_info')
# 로그 추가
print(f"세션 데이터 확인: game_name={game_name}, tag_line={tag_line}, tier_info={tier_info}")
if not game_name or not tag_line or not tier_info:
return render(request, 'riot_api/error.html', {'error_message': "필수 정보가 누락되었습니다. 다시 시도해주세요."})
# 스트리머 폼 데이터 확인 및 저장
streamer_form = StreamerForm(request.POST)
if streamer_form.is_valid():
streamer_name = streamer_form.cleaned_data['streamer_name']
# `StreamerTier` 데이터 저장
StreamerTier.objects.create(
streamer_name=streamer_name,
summoner_name=f"{game_name}#{tag_line}", # 태그라인 포함한 소환사 이름 저장
game_name=game_name, # 소환사 이름
tag_line=tag_line,
tier=tier_info['tier'],
rank=tier_info['rank'],
league_points=tier_info['leaguePoints'],
wins=tier_info['wins'],
losses=tier_info['losses'],
)
return redirect('streamer_tier_list')
else:
return render(request, 'riot_api/error.html', {'error_message': "스트리머 닉네임이 유효하지 않습니다."})
else:
return redirect('summoner_tier')
(1) 전적정보를 검색하고 해당 정보를 스트리머 티어표로 저장하고 싶으면 관리자 계정만 하도록 하였습니다.
(2) post요청이 오면 닉네임,태그라인,티어정보를 확인하도록합니다.
(3) 이 3개의 정보가 없으면 에러를 발생시킵니다.
(4) 저장 버튼을 눌러서 post요청이 확인되면 원하는 정보를 저장하도록 합니다.
2) 스트리머 티어리스트 목록
def streamer_tier_list(request):
query = request.GET.get('q')
sort_order = request.GET.get('sort', 'alphabetical') # 기본 정렬 기준은 알파벳순
if query:
streamer_tiers = StreamerTier.objects.filter(streamer_name__icontains=query)
else:
streamer_tiers = StreamerTier.objects.all()
# 승률 계산 후 객체에 추가
streamer_tiers = streamer_tiers.annotate(
win_rate=ExpressionWrapper(
F('wins') * 100 / (F('wins') + F('losses')),
output_field=FloatField()
)
)
# 정렬 기준 적용
if sort_order == 'tier_desc':
streamer_tiers = sorted(streamer_tiers, key=lambda x: (x.tier_priority, -x.league_points), reverse=True)
elif sort_order == 'tier_asc':
streamer_tiers = sorted(streamer_tiers, key=lambda x: (x.tier_priority, x.league_points))
elif sort_order == 'alphabetical':
streamer_tiers = streamer_tiers.order_by('streamer_name')
paginator = Paginator(streamer_tiers, 10) # 페이지당 10개
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'riot_api/streamer_tier_list.html', {
'page_obj': page_obj,
'is_superuser': request.user.is_superuser,
'sort_order': sort_order, # 현재 정렬 기준 전달
'query': query, # 현재 검색어 전달
})
(1) 스트리머 목록에는 본인이 원하는 스트리머를 검색하도록 하는 쿼리문을 넣도록합니다.
(2) 또한 정렬기능을 통해 티어 순서를 확인하도록 하였습니다.
3) 제거 또는 업데이트
def delete_streamer_tier(request, pk):
if not request.user.is_superuser: # 슈퍼유저 권한 확인
return HttpResponseForbidden("이 작업은 관리자만 수행할 수 있습니다.")
streamer_tier = get_object_or_404(StreamerTier, pk=pk)
streamer_tier.delete() # 데이터 삭제
return redirect('streamer_tier_list') # 스트리머 티어 리스트로 리디렉션
def update_streamer_tiers(request):
if request.method != 'POST':
return JsonResponse({"status": "error", "message": "Invalid request method"}, status=405)
# 요청 제한 (캐시 키 생성)
cache_key = f"update_tiers_{request.user.id}"
if cache.get(cache_key):
return JsonResponse({"status": "error", "message": "잠시 후 다시 시도해주세요."}, status=429)
messages = []
streamer_tiers = StreamerTier.objects.all()
for streamer in streamer_tiers:
game_name = streamer.game_name
tag_line = streamer.tag_line
# PUUID 가져오기
puuid = get_puuid_by_riot_id('asia', game_name, tag_line, settings.RIOT_API_KEY)
if not puuid:
messages.append(f"PUUID를 가져올 수 없습니다: {streamer.summoner_name}")
continue
# 소환사 정보 가져오기
summoner_info = get_summoner_by_puuid('kr', puuid, settings.RIOT_API_KEY)
if not summoner_info:
messages.append(f"소환사 정보를 가져올 수 없습니다: {streamer.summoner_name}")
continue
encrypted_summoner_id = summoner_info.get('id')
if not encrypted_summoner_id:
messages.append(f"소환사 ID를 가져올 수 없습니다: {streamer.summoner_name}")
continue
# 티어 정보 가져오기
league_entries = get_league_entries_by_summoner_id('kr', encrypted_summoner_id, settings.RIOT_API_KEY)
if not league_entries:
messages.append(f"티어 정보를 가져올 수 없습니다: {streamer.summoner_name}")
continue
# 가장 높은 티어 정보 선택
tier_info = None
for entry in league_entries:
if entry['queueType'] == 'RANKED_SOLO_5x5':
tier_info = entry
break
if not tier_info:
tier_info = league_entries[0]
# StreamerTier 객체 업데이트
streamer.tier = tier_info['tier']
streamer.rank = tier_info['rank']
streamer.league_points = tier_info['leaguePoints']
streamer.wins = tier_info['wins']
streamer.losses = tier_info['losses']
streamer.save()
messages.append(f"업데이트 완료: {streamer.streamer_name}")
# 요청 제한 시간 설정 (1분)
cache.set(cache_key, True, timeout=60)
# 리디렉션으로 티어 목록 페이지로 이동
return redirect('streamer_tier_list')
(1) 관리자만이 제거할수 있도록하였습니다.
(2) 업데이트는 비로그인 사용자도 사용할 수 있게 설정하였습니다
(3) 다만 악용의 가능성이 있어서 한번 누르게 된다면 1분의 대기시간을 가지도록 하였습니다.
(4) 업데이트 또한 전적정보처럼 같은 방식으로 하도록 하였습니다.
ps)이러면 저장된 정보가 많아지면 요청도 오래걸릴거같은 생각이 드네요
4. 후기

이렇게 이름순 티어순이 잘 작동되는지 확인하였고 관리자 계정으로 로그인시 삭제 버튼이 보이도록 하였습니다.
또한 업데이트를 누르면 그 즉시 반영되나 1분안에 누를경우 에러가 발생하도록 하였습니다.
후에는 이제 보안강화를 위해 이메일인증이나 소셜로그인 그리고 비밀번호 변경 및 비밀번호 규칙설정을 할 예정입니다.
'Django 개인프로젝트 > 첫번째 프로젝트' 카테고리의 다른 글
| 10. Django를 이용한 댓글 및 마이페이지 구현 (1) | 2024.11.18 |
|---|---|
| 9. Django와 html을 이용해 로그인후 글쓰기 연동 (2) | 2024.11.11 |
| 8. 회원가입 기능 개선 (1) | 2024.11.08 |
| 7. html 템플릿 Django프로젝트 (1) (3) | 2024.11.05 |
| 6. Django와 RiotAPI를 이용한 전적정보 저장 (0) | 2024.10.30 |