Django-toy) 따릉이 현황 알림 서비스

Mongle·2020년 8월 28일
0

ToyProject

목록 보기
2/3

👉 영상으로 보기

따릉이 실시간 현황 관리 서비스

😀 기획의도

json은 데이터를 주고 받을 때 가장 널리 쓰이는 방식이다. json형식으로 받은 공공 데이터를 가공하고 사용자에게 서비스해보자.
서울열린데이터광장 - 서울특별시 공공자전거 실시간 대여정보

🧐 방법

udemy강의를 통해 공부했다.
강의에서는 air now의 미세먼지 데이터를 사용했지만 air now는 미국의 미세먼지 데이터만 제공하고 있다. 우리나라의 미세먼지 데이터를 제공하는 공공 api를 찾다가 이미 비슷한 서비스가 굉장히 많다는 것을 알게되었고, 유용하게 사용할 수 있는 따릉이 현황을 서비스하기로 했다.


🤓 학습 내용

request 모듈

Requests allow you to send HTTP/1.1 requests. You can add headers, form data, multipart files, and parameters with simple Python dictionaries, and access the response data in the same way. It’s powered by httplib and urllib3, but it does all the hard work and crazy hacks for you.
출처 - https://pypi.org

request모듈을 통해 json 요청하고 파싱하기

http요청을 처리해주는 모듈이다. json과 함께 사용하면 기본적인 http 요청을 보내는 것 이외에도 추가적인 data를 함께 처리할 수 있어서 활용도가 높다.


deserialize
<보완 예정>


🥴 문제 상황

Django에서 for idx in range()로 여러 데이터를 한 페이지에 출력하려고 했으나...
django.template.exceptions.TemplateSyntaxError:
장고는 for in range()를 지원하지 않는다.😂

<h3>따릉이를 보여줘</h3>

{% if api %}
    {% if api == "Error..." %}
        There was an error. please try again
    {% else %}
        
        <br>
        <div class="card">
            <div class="card-header">
                {{ api.rentBikeStatus.row.0.stationName }}
            </div>
            <div class="card-body">
              <h5 class="card-title">parkingBikeTotCnt : {{ api.rentBikeStatus.row.0.parkingBikeTotCnt }}</h5>
              <p class="card-text"><br>
                rackTotCnt : {{ api.rentBikeStatus.row.0.rackTotCnt }}<br>
                shared : {{ api.rentBikeStatus.row.0.shared }}</p>
              
            </div>
        </div>
        <br>
        <div class="card">
            <div class="card-header">
                {{ api.rentBikeStatus.row.1.stationName }}
            </div>
            <div class="card-body">
              <h5 class="card-title">parkingBikeTotCnt : {{ api.rentBikeStatus.row.1.parkingBikeTotCnt }}</h5>
              <p class="card-text"><br>
                rackTotCnt : {{ api.rentBikeStatus.row.1.rackTotCnt }}<br>
                shared : {{ api.rentBikeStatus.row.1.shared }}</p>
              
            </div>
        </div>

(데이터는 잘 받아왔다.😀)

두 가지 방법으로 해결할 수 있을 것 같다.
1. filter를 사용하는 방법(관련 내용을 찾아본 후 적용시켜야한다.)
2. 전체 데이터를 리스트로 변환한 후 리스트 자체를 for문으로 돌려서 값을 가지고 오는 방법

😎 해결방법

2번 방법으로 문제를 해결했다.
for idx in range()를 사용하지 않고 for문으로 전체 데이터를 순서대로 불러올 수 있었다.

가정에서 한 가지 오류가 있었던 부분은 데이터가 리스트 형태로 온게 아니라 딕셔너리 형태로 와서 그 부분을 수정해주었다.

기존의 view에서는 json형식으로 받아온 api를 그대로 html파일에 던졌지만 필요한 데이터만 보내기 위해서 api["rentBikeStatus"]["row"] 부분만 api_dict로 저장해서 보낸다.

view.py

def home(request):
    import json
    import requests

    api_request = requests.get("http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/bikeList/1/99")
    
    try : 
        api = json.loads(api_request.content) #api_request가 잘 가져왔으면 데이터를 json으로 파싱해서 저장하고,
        api_dict = api["rentBikeStatus"]["row"] # 필요한 부분만 가공해서 보냄.
    except Exception as e:
        api = "Error..."
        
    return render(request, 'home.html', {'api':api,'api_dict':api_dict})

home.html

        {% for value in api_dict %}
            <br>
            <div class="card">
                <div class="card-header">
                    {{ value.stationName }}
                </div>
                <div class="card-body">
                <h5 class="card-title">parkingBikeTotCnt : {{ value.parkingBikeTotCnt }}</h5>
                <p class="card-text"><br>
                    rackTotCnt : {{ value.rackTotCnt }}<br>
                    shared : {{ value.shared }}</p>
                </div>
            </div>
            <br>
        {% endfor %}

api_dict의 value를 for문으로 돌면서 필요한 요소만 뽑아서 출력한다.


💡 key point)

문제 해결의 포인트는

api_dict = [{ value1 },{ value2 },{ value3 },{ value4 },...,{ last value }]

value = {'rackTotCnt': '22', 'stationName': '102. 망원역 1번출구 앞', 'parkingBikeTotCnt': '17', 'shared': '0', 'stationLatitude': '37.55564880', 'stationLongitude': '126.91062927', 'stationId': 'ST-4'}

데이터의 구조를 관찰하여 리스트와 딕셔너리를 구분해서 필요한 데이터를 추출하는 것이었다.


😺 추가 기능 - 검색

검색 기능을 추가했다. 데이터의 양이 많다보니 필요한 데이터만 검색하는 기능이 필요해보였다.
처음에는 새로운 search라는 페이지에 검색한 데이터를 넘겨줄까 생각했지만 추출한 데이터를 새로운 url에 할당해서 페이지 전환을 하는 것 보다 post방식으로 구현하면 페이지 전환 없이 더 간단하고 깔끔한 코드가 될 것 같았다.

👉 post방식으로 구현해서 기존의 url에 그대로 출력

base.html

<form action="{% url 'home' %}" class="form-inline my-2 my-lg-0" method="POST">
{% csrf_token %}
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="station">
<button class="btn btn-outline-info my-2 my-sm-0" type="submit">Search</button>
</form>

form으로 받은 데이터를 post방식, name="station"으로 view로 넘겨준다.

view.py

if request.method == "POST":
        station = request.POST['station'] # 추가된 부분

        api_request = requests.get("http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/bikeList/1/99")
        
        try : 
            api = json.loads(api_request.content) 
            api_dict = api["rentBikeStatus"]["row"]
        except Exception as e:
            api = "Error..."
        return render(request, 'home.html', {'api':api,'api_dict':api_dict,'station':station})
    else:
    
    #...생략...

view에서 station이라는 템플릿변수로 home.html에 던진다.

home.html

{% if station %}
    {% for value in api_dict %}
        {% if station in value.stationName %} #문자열 안에 문자열이 포함되는지 확인할 때 간단하게 표현할 수 있다.
        {{ station}}        
        <br>
        <div class="card ">
            <div class="card-header ">
                {{ value.stationName }}
            </div>
            <div class="card-body">
            <h5 class="card-title">parkingBikeTotCnt : {{ value.parkingBikeTotCnt }}</h5>
            <p class="card-text"><br>
                rackTotCnt : {{ value.rackTotCnt }}<br>
                shared : {{ value.shared }}</p>
                
            </div>
        </div>
        <br>
        {% endif %}
    {% endfor %}

{% else %}

관련코드는 여기에서 확인하세요

👀 Tip) {% if station in value.stationName %}
검색값 station이 value.stationName에 포함되면 true를 반환하고 포함되지 않으면 false를 반환한다.


😸 마치며

정말 재미있게 집중해서 완성한 프로젝트다. 시간 가는 줄 몰랐다😁

👉 결과물 영상으로 보기 : 따릉이 실시간 현황 관리 서비스
👉 전체 소스코드 : jeongseo21/ttareung_toy_project

profile
https://github.com/Jeongseo21

0개의 댓글