ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Django를 활용한 리그오브레전드 전적 검색 사이트
    ML, DL & Python/Django 2019. 6. 17. 00:19

     

    안녕하세요.

     

    요즘 파이썬으로 개발하는 Django(이하 장고) 프레임워크에 대해서 공부를 하고 있는데요, 장고는 매우 손 쉽게 어플리케이션을 만들고 서버를 통해서 웹을 만들 수 있는 강력한 웹 프레임워크입니다.

     

    장고는 트위터 개발자들이 개발을 하는 과정에서 항상 어느정도 비슷한 부분이 있기에 어디에서도 공용으로 사용할 수 있는 프레임워크를 개발한 것이 이 장고입니다.

     

    장고에 대한 간략한 설명은 따로 포스팅할 예정이며 지금은 바로 장고를 사용하여 간단한 롤 전적 사이트를 만들어 보겠습니다. 

     

    먼저 제가 앞선 포스팅에서 라이엇 api를 통해서 리그오브레전드의 데이터를 수집하는 것을 알아보았습니다. 

    여기서 알아두셔야 할 부분은 소환사 닉네임과 닉네임을 통해서 반환받은 id 키 값, 그리고 그 키 값을 이용하여 각 소환사의 리그 정보를 알아보는 과정을 거치는 것입니다.

     

    이번 포스팅에서 사용할 api flow

     

    자 그럼 순차적으로 진행해보겠습니다.

     

    장고를 통해서 웹을 만들기 위한 준비를 진행합니다. 여기서는 자세히 다루지 않을 것이므로 파일의 구조만 보여드리겠습니다.

     

     

    1. lolsearch/lolsearch/settings.py 설정

     

    Settings.py에 들어가서 코드를 수정할 것이다. 먼저 간략히 설명하자면 우리가 직접 html도 만지고 프론트 코드를 다루는 것은 score에서 대부분 이뤄집니다. 즉, lolsearch에 있는 부분들은 빙수로 비유하자면 빙수를 담는 그릇을 의미합니다. 따라서 큰 틀을 먼저 잡아주고 경로 등을 설정해줘야합니다.

     

    settings.py의 installed_apps부분을 확인해봅시다. 여러분들은 django로 시작하는 text밖에 보이지 않으실텐데요. 이부분에 score를 추가해줍니다.

    나머지 부분들은 장고의 기초세팅 부분들과 동일합니다.

     

     

    2.lolsearch/lolsearch/urls.py 설정

     

    urls의 경로를 지정해주는 매우 중요한 과정입니다. 하지만 아까 말했듯이 lolsearch는 그릇이라고 말씀드렸죠. 즉, 여기서도 score가 자유롭게 코드를 변환할 수 있도록 도와주는 세팅을 해줘야하는데요, 밑에 처럼 하시면 됩니다!

     

    django.urls라이브러리에서 path와 include를 임포트해오는 것을 잊지마세요!

    include는 이제 곧 만들 score/urls의 경로를 모두 포함하여 따로 lolsearch/urls.py의 설정을 바꾸지 않아도 자동으로 모두를 포함하여 경로를 설정해주는 함수입니다.

     

    여러분들 코드 있는 그대로에서 저와 다른 부분만 수정해주시면 됩니다.

     

     

    3. lolsearch/score/url.py 세팅

     

    그 다음으로 score의 url.py의 코드를 수정해보겠습니다. score는 뭐고 urls.py는 어디있냐고요? 다음 과정을 거치시면 됩니다.

    여러분들의 커맨드 창은 현재 (여러분들의 로컬)/lolsearch/lolsearch 이정도의 경로밖에 지정되어 있지 않겠죠? 자 경로를 (여러분들의 로컬)/lolsearch 로 먼저 만들어 놓겠습니다.(아마 초기 커맨드 경로는 대부분 여러분들 로컬일테니 cd "여러분들이 만든 장고 초기 앱" - 즉, 저는 장고를 처음 만들 때 장고 초기 앱 이름을 "lolsearch"로 만든 것입니다.)

     

    경로가 로컬/lolsearh 로 맞추셨나요? 그럼 커맨드 창에 python manage.py startapp score 라고 입력하세요 그러고 lolsearch를 들어가보면 score파일이 만들어져 있는 것을 확인할 수 있습니다.

     

    이제 여기서 여러분들은 모델을 수정하고 view함수를 만들고 동적 템플릿, admin으로 관리 등을 하실 수 있습니다.

     

    그러면 score파일에 urls.py 파일을 만듭니다. 그런 다음 url경로들을 지정해보겠습니다.

     

    우리가 필요한 것은 일단 소환사 이름을 검색할 수 있는 창과 검색한 결과가 나오는 창 두개가 필요합니다.

    경로가 두개 필요하겠죠? 만들어봅시다! 빨강 박스만 보시면 됩니다.

     

    자 이렇게 만드신 후에 다시 커맨드 창에 돌아와서 python manage.py runserver를 입력해볼까요?

     

    에러가 뜨거나 아예 커맨드 창에서 막혀버리겠죠? 당연한 결과입니다. 저희는 아직 views.py에서 함수를 하나도 입력하지 않았거든요!

     

     

     

    4. lolsearch/score/views.py 설정

     

    이제 views.py에서 함수를 만들어볼까요? 여기서 만드는 함수는 python기반이므로 python 을 이해하고 코드를 치면서 확인하거나 직접 코드를 분할해서 여러 방면으로 데이터가 어떻게 api로 수집이 되고 어떤 형식으로 나오는지 확인하시길 바랍니다.

     

    views에서 저희가 만들 함수는 두개입니다. urls.py에서도 보셨다시피 score_view, search_result입니다. 왜냐하면 url을 통해서 웹은 이동하는데 score/urls.py를 보시면 views.score_view라고 되어 있고 경로가 ''로 비어있습니다. 이는 서버를 실행하면 바로 views.py로 가서 score_view 함수를 호출하는 것입니다. 그럼 views.py의 score_view함수는 요청받아 자기의 데이터를 웹으로 내보내는 과정을 거칩니다.

     

    사실 score_view함수는 별게 없습니다. 그래서 score_view는 html코드에 녹여내는 과정이 중요합니다. 이유는 소환사 닉네임을 받아와서 text형태로 search_result함수로 넘겨줘야하기 때문입니다.

     

    그럼 함수를 만들어 봅시다.

    #LOL 전적 검색
    def score_view(request): #urls에 만들었던 함수
        return render(request,'score/score_view.html')
        
    #검색결과 함수
    def search_result(request):
        if request.method == "GET":
            summoner_name = request.GET.get('search_text') #score_view html에서 넘겨 받은 text
     
            summoner_exist = False
            sum_result = {}
            solo_tier = {}
            team_tier = {}
            store_list1 = []
            store_list2 = []
            game_list ={}
            game_list2 = []
            api_key = 'RGAPI-005f5231-bf23-4a84-bac8-ce8169514e19' #부여받은 api
     
     
            summoner_url = "https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/" + str(summoner_name)    #소환사 정보 검색 - 넘겨받은 텍스트를 이용하여
            params = {'api_key': api_key}
            res = requests.get(summoner_url, params=params)
            # summoners_result = json.loads(((res.text).encode('utf-8')))
            if res.status_code == requests.codes.ok: #결과값이 정상적으로 반환되었을때만 실행하도록 설정(response200)
                summoner_exist = True
                summoners_result = res.json() #response 값을 json 형태로 변환시키는 함수
                if summoners_result: #만약 summorners_result가 값이 존재한다면
                    sum_result['name'] = summoners_result['name'] # 소환사 닉네임
                    sum_result['level'] = summoners_result['summonerLevel'] #소환사 레벨
                    sum_result['profileIconId'] = summoners_result['profileIconId'] #소환사 프로필코드(프로필도 api를 통해서 받아야함)
     
                    tier_url = "https://kr.api.riotgames.com/lol/league/v4/entries/by-summoner/" + summoners_result['id']    #소환사 티어(랭크게임) 검색
                    tier_info = requests.get(tier_url, params=params)
                    tier_info = tier_info.json() #리그 정보 값을 json으로 변환
     
                    if len(tier_info) == 1:     #자유랭크 또는 솔로랭크 둘중 하나만 있는경우
                        tier_info = tier_info.pop() #json의 맨 마지막 요소를 반환해주고 반환된 값을 삭제해주는 함수
                        if tier_info['queueType'] == 'RANKED_FLEX_SR':        #자유랭크인 경우
                            team_tier['rank_type'] = '자유랭크 5:5'
                            team_tier['tier'] = tier_info['tier']
                            team_tier['rank'] = tier_info['rank']
                            team_tier['points'] = tier_info['leaguePoints']
                            team_tier['wins'] = tier_info['wins']
                            team_tier['losses'] = tier_info['losses']
                        else:#솔로랭크인 경우
                            solo_tier['rank_type'] = '솔로랭크 5:5'
                            solo_tier['tier'] = tier_info['tier']
                            solo_tier['rank'] = tier_info['rank']
                            solo_tier['points'] = tier_info['leaguePoints']
                            solo_tier['wins'] = tier_info['wins']
                            solo_tier['losses'] = tier_info['losses']        
                    if len(tier_info) == 2:            #자유랭크, 솔로랭크 둘다 전적이 있는경우
                        for item in tier_info:
                            if 'FLEX' in item['queueType']: #flex = 자유랭크일 떄
                                store_list1.append(item)
                            else:
                                store_list2.append(item)#솔로랭크일 때
                        solo_tier['rank_type'] = '솔로랭크 5:5'
                        solo_tier['tier'] = store_list2[0]['tier']
                        solo_tier['rank'] = store_list2[0]['rank']
                        solo_tier['points'] = store_list2[0]['leaguePoints']
                        solo_tier['wins'] = store_list2[0]['wins']
                        solo_tier['losses'] = store_list2[0]['losses']
     
                        team_tier['rank_type'] = '자유랭크 5:5'
                        team_tier['tier'] = store_list1[0]['tier']
                        team_tier['rank'] = store_list1[0]['rank']
                        team_tier['points'] = store_list1[0]['leaguePoints']
                        team_tier['wins'] = store_list1[0]['wins']
                        team_tier['losses'] = store_list1[0]['losses']
     
     
            return render (request, 'score/search_result.html', {'summoner_exist': summoner_exist, 'summoners_result': sum_result, 'solo_tier': solo_tier, 'team_tier': team_tier})
        #return에 있는 값은 html로 위와 같은 데이터를 보낸다는 뜻이다.

    코드는 참고한 사이트에서 주석처리한 후 조금 수정했습니다.

     

    자 이제 웹에서 저희가 만든 함수와 어떻게 값들이 도출되는지 확인해봐야겠죠?

    (지금은 아무것도 보이지 않는 상태이거나 에러가 나오는 상태일 것입니다. 이유는 다음 step에서)

     

     

     

    5. html파일 만들기

     

    html은 대표적인 정적 함수입니다. 

    이제 이러한 html코드를 이용하여 저희가 만든 코드를 웹상에서 보이고 실행할 것입니다.

     

    장고에서는 이러한 html을 템플릿이라고 말합니다. 즉, 내가 백에서 구현한 모델이나 함수를 이용하여 데이터가 html상에 보일 수 있도록 하는 것입니다.

     

    템플릿 파일을 만들어 보겠습니다. score파일에 새폴더를 만들고 이름을 templates로 바꾸겠습니다. 그리고 templates파일에 score라는 새폴더를 만들겠습니다.

     

    여기서 왜 또 score폴더를 새로 만드는것이지? 라는 의문을 가지고 계신 분들도 있을 것입니다.

     

     이유는 templates를 관리함에 있어서 처음 score폴더에서 html파일을 만들게 된다면 urls.py에 있는 path가 views함수를 호출하고 거기서 html을 불러오는 과정에서 충돌이 일어날 수 있기 때문입니다.

     물론, score폴더에서 html파일을 가져오라는 명령은 똑같기 때문에 templates폴더를 만들어서 그안에 score폴더를 만들고 score폴더안에 html파일을 만들어서 관리하는 것이 충돌 위험도 막고 따로 관리하기가 용이 합니다.

     

    (컴퓨터는 똑똑하기 때문에 lolsearch/score/.html  /  lolsearch/score/templates/score/.html 을 동일하게 인식합니다.)

     

    위에서 에러가 났었죠? 이유는 views의 두 함수를 확인하면 render을 통해서 url을 request받아서 score/.html 파일을 불러옵니다. 하지만 저희는 아직 html코드를 만들지 않았기 때문에 오류가 나는 것입니다.

     

    먼저 score_view함수가 호출하는 score_view.html을 확인하겠습니다.

     

     

    5-1. score_view.html / score_results.html 파일을 아래의 링크를 타고 넘어가셔서 어디있는지는 위의 내용을 충실히 따라오신분들은 알고 계시겠죠??

     

    minyong-shin/my-lol-search

    Contribute to minyong-shin/my-lol-search development by creating an account on GitHub.

    github.com

    음... 일단 저는 전적검색 말고도 커뮤니티 페이지도 만들고 있는 단계여서 html코드상에서 문제와 여러분들은 만들고 계시지 않은 단계이므로 무조건 에러가 나올 수 있을 것 같은데요.

     

    먼저 score_view.html 의 html코드에서는 body태그에서는 <div class="community-header">태그 밑의 영역은 모두 없애셔도 됩니다. 그러면 아마 여러분들의 html코드에서는 부트스트랩과 <div class="page-header">~~<div class="container">부분만 남아 계실 겁니다!

     

    아 맞다 그리고 제 깃허브 파일에서 static폴더 안에 있는 lol.css파일을 받아서 같은 경로상에 다운로드 받아놓아주시면 좋을 것 같습니다. 아니면 <!doctype html>  밑에 {% load static %} 와 head태그 부분의 맨밑의 css/lol.css 라고 써있는 코드는 삭제해주시면 되겠습니다. 

     

     

     

    6. 웹페이지 확인

     

    score_view 홈페이지 메인 화면

    만약 css파일을 안받으신 분들이라면 이와 같이 나오지 않으실 겁니다!

     

    다음으로 소환사 닉네임을 소환사명에 입력해볼까요?

    저는 skt t1 teddy 를 입력해봤습니다.

     

    search_result 검색결과 화면

    보시다시피 소환사 아이콘뱃지는none값으로 되어 있는데 이는 제가 api로 소환사 아이콘 뱃지 이미지를 안받았기 때문입니다. 아이콘 뱃지는 코드형식으로 되어 있는데 아이콘 뱃지까지 노출시키고 싶으시다면 아이콘 뱃지 이미지를 다운로드한 후 뱃지 코드와 매칭시키신다음 html 코드를 작성하면 정상적으로 노출이 될 것입니다.

     

     

     

     

    자 장고로 리그오브레전드 간략한 전적검색 웹을 만들어봤는데요. op.gg나 인벤, 여타 다른 전적 검색 사이트에 비해서 세발의 피도 안되는 결과물입니다. 하지만 이런 api를 이용해서 데이터도 불러오고 그것을 이용하여 웹상에 올려서 나만의 전적검색을 만들어 본 것은 뿌듯한 경험이 아닐수가 없었습니다. ㅎㅎ

     

    지금 저는 django의 버젼을 git을 활용하여 관리하고 있는데요. 여러분들도 git을 사용하여 관리하시면 훨씬 손쉽게 관리하실 수 있습니다. 또한 git과 pythonanywhere를 통해서 다른사람도 이용할 수 있는 저만의 도메인을 만들었는데 이는 다른 포스팅에서 설명하도록 하겠습니다.

     

    마지막으로 지금은 op.gg의 커뮤니티처럼 직접 글을 쓰고 댓글을 달고 하는 게시판 형식의 부분을 만들고 있는데요. 조만간 완성해서 돌아오겠습니다. 감사합니다!!

     

     

     

    참고한 site link: https://tutorial.djangogirls.org / https://sundrystore.tistory.com/26


    댓글 2

Designed by Tistory.