상세 컨텐츠

본문 제목

Django_자산관리 W_P_Project_02..[아파트 시세 조회]

Django

by Digit_Kim 2023. 11. 11. 14:31

본문

  자산(Asset)에서 가장 큰 portion을 차지하는 부동산, 그 중에서 내 아파트와 주변의 실제 거래된 내역을 조회하여 내 자산을 평가할 수 있다.

 

  국토교통부에서 수시로 업데이트하는 실제 거래자료를 open api를 활용하여 내 project에서 확인할 수 있도록 한다.

 

  공공데이터포털 홈페이지(https://www.data.go.kr/)에 들어가서, 로그인을 한다.(나의 경우 NAVER로 로그인)

 

   검색 창에서 [국토교통부 아파트매매 실거래 상세 자료]를 입력하면 리스트가 나타나는데, 오픈 API쪽에 있는 링크를 클릭한 후 [활용신청]을 눌러 진행한다. 신청이 완료되면 개인 인증키가 발급되며 그 인증키를 가지고 코딩을 해야 한다.

 

  여기까지 간략히 설명했는데, 초보자분들은 아마 세부 사항들에서 혼란을 느낄수도 있지만 이해해 주시길...

 

  본격적으로 Django를 통한 코딩으로 넘어간다.

  

  미리 urls.py에 다음과 같이 정의해 놓는다.

 

from django.urls import path
from . import views

urlpatterns = [
    path('estate/', views.estate, name='estate'),
    path('filtered_estate/', views.filtered_estate, name='filtered_estate'),
]

 

 

 

'estate/' 는 기본 html을 열 때 사용하며, 'filtered_estate/'는 열려진 html에서 추가적인 검색을 할 때 사용하는 url이다.

 

  그럼 views.py에서 estate 모듈을 만들어 본다. 지금은 여러 시행착오를 한 이후라서 조금만 시간을 더 들이면 내가 직접 만들 수도 있겠지만, 여기서는 PYPI란 모듈을 활용할텐데 나름 편리하게 만들어 놓아서 쉽게 사용할 수가 있는 장점이 있다.

 

from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect, get_object_or_404
import requests
import json            
import xmltodict       
import pandas as pd
from datetime import datetime,date,timedelta,time

 

 

  처음 html을 볼러 올 함수( 'estate')를 정의하겠다.

 

def estate(request):
    # 서비스키 할당하기
    service_key = ""  #일반 인증키(Decoding)을 복붙하면 된다.

    # 데이터 조회 인스턴스 만들기
    from PublicDataReader import TransactionPrice #이 모듈을 불러오기 위해 터미널창에서 pip install PublicDataReader --upgrade을 실행시켜야 한다. 
    api = TransactionPrice(service_key)

    today = datetime.now()  #검색기간을 위해 불러올 오늘 날짜
    first_day_of_year = datetime(today.year, 1, 1) #초기 검색기간의 처음을 나타낼 년초날짜

    start_date=first_day_of_year.strftime('%Y%m') #검색기간 형식'YYYYMM'에 맞춰 변경
    end_date=today.strftime('%Y%m')
    sigungu_name ="이천시" #default 시군구명으로 지정함
    updong='증포동' #default 읍면동으로 지정함.
 
    # 시군구코드 조회하기
    import PublicDataReader as pdr    
    code = pdr.code_bdong()  #PYPI를 만든 사람들이 시군구명으로 시군구코드를 찾을 수 있게 만든 모듈
    filtered_code = code.loc[(code['시군구명'].str.contains(str(sigungu_name)))]

    # 특정 기간 자료 조회하기
    df = api.get_data(
        property_type="아파트",
        trade_type="매매",
        sigungu_code=filtered_code['시군구코드'],
        start_year_month=start_date,
        end_year_month=end_date,
        #year_month=start_date,  # 특정 년월 자료만 조회하기
    )
    filtered_df=df[df['법정동'] == '증포동']

    context = {
        'items': filtered_df,
        's_date':start_date,
        'e_date':end_date,
        'city':sigungu_name,
        'updong':updong,
    }

    return render(request, 'core/property.html', context)

 

 

 

위의 19번째 줄의 "code = pdr.code_bdong()"는 PYPI 모듈에서 만든 것이지만, 범정동코드 전체자료를 Down받은 후에 이 파일을 활용하여 간단하게 만들수도 있다. 아래 파일은 내가 다운받은 것임.

법정동코드 전체자료.txt
2.73MB

 

  이제 html을 만들어 불러오면 '경기도 이천시'의 '증포동'지역의 아파트가 '2023년1월 ~2023년11월' 기간동안 거래된 내역이 보여진다.

 

아래는 property.html의 불러오는 부분이다.

 

{% extends "Core/layout/base.html" %}  /*기본 lqyout 불러오기
{% block content %}

{% load humanize %} /* 숫자를 천원단위 표시하기

<body>
    <h2 style="color: blue; margin-left: 15px;">아파트 거래 시세 조회</h2>
      <button onclick="history.back()">이전으로</button>
      <button onclick="location.href='/home/'">Home</button>
      <button onclick="location.href='/list_asset/'">자산 리스트</button>
      <button onclick="location.href='/anal_asset/'">자산분석</button>
      <hr><br>
    <br>
  
    <form method="GET" id="search-form">
        {% csrf_token %}
        <td>
            기준년월: 
            <input type="text" id="s_date" name="s_date" value="{{s_date}}" placeholder="YYYYMM">
            <input type="text" id="e_date" name="e_date" value="{{e_date}}" placeholder="YYYYMM">
            <input type="text" id="city" name="city" value="{{city}}" placeholder="시군구명">
            <input type="text" id="updong" name="updong" value="{{updong}}" placeholder="읍면동">
        </td>
        <button type="submit" class="ui primary button">검색</button>
    </form>
    <div style="height: 700px; ">
        <table id="search_table" style="height:100%; overflow: scroll;">
            <tr>
                <th>도로명</th>
                <th>시군구코드</th>
                <th>법정동</th>
                <th>지번</th>
                <th>아파트</th>
                <th>전용면적</th>
                <th>거래금액</th>
                <th>건축년도</th>
                <th>년월</th>
            </tr>
            {% for index, row in items.iterrows %}
                <tr>
                    <td>{{ row.도로명 }}</td>
                    <td>{{ row.도로명시군구코드}}</td>
                    <td>{{ row.법정동}}</td>
                    <td>{{ row.지번}}</td>
                    <td>{{ row.아파트}}</td>
                    <td>{{ row.전용면적}}</td>
                    <td>{{ row.거래금액|intcomma}}</td>
                    <td>{{ row.건축년도}}</td>
                    <td>{{ row.년}}{{ row.월}}</td>

                </tr>
            {% endfor %}
        </table>
    </div>

</body>

{% endblock content %}

 

 

 

 위의 코딩을 하면 views.py를 통해 불러온 데이터들이 html상에 뜨게 된다. 여기에 CSS를 통해서 style을 좀 갖추려면 아래와 같은 부분을 <body> 위쪽에 만들면 된다.

 

<style>
    table{
    border: 1px solid lightblue; /*테이블 외곽선을 
    }
    th{                          /*테이블의 header를 고정하고 넓이와 높이와 색상을 정한다. 
        height: 40px;
        width: 120px;
        text-align: center;
        background-color: aquamarine;
        position: sticky;
        top: 0;
    }
    tr{                            /* 테이블 행(줄)의 높이와 정렬을 정한다.
        height: 30px;
        text-align: center;
    }
    tr:hover {                      /* 테이블 행(줄)에 마우스가 올려질 때 색상 및 포인터 모양
        background-color: bisque;
        cursor: pointer;
    }
    input[type="text"]{              /* 검색 텍스트의 모양과 위치와 크기를 만든다.
        border: 1px solid lightpink;
        border-radius: 7px;
        text-align: center;
        height:35px;
        font-size: 14px;
        margin-bottom: 20px;
        margin-left: 5px;
        padding: 5px;
    }
    #s_date,#e_date{
        width: 80px;
    }
    button{                                                        /*네비게이션 역할의 버튼의 모양
        border: 1px solid lightgrey; /* 옅은 회색 테두리 설정 */
        border-radius: 5px; /* 사각형 모서리를 부드럽게 설정 */
        margin-top: 10px;
        cursor: pointer;
    }
    button:hover {
        background-color: lightcoral;
        border: 1px solid blueviolet;
        color: white;
    }
</style>

 

 

위와 같이 코딩을 하면 다음과 같은 화면이 브라우저창에 뜬다.

 

 

 

  자 그 다음에는 default '시군구명' 및 '읍면동'이 아닌 내가 검색하고 싶은 '시군구'. '읍면동' 그리고 기간을 설정한 후 검색 버튼 혹은 Enter ket를 누를 때 나타나게 하는 부분을 살펴보자.

 

  우선 클라이언트 즉, html에서 Django의 views.py에 보내주어야 한다.  여기서부터는 javascript가 필요해 진다. 작성한 코드는 일반적으로 <style> 밑에 해 놓는다.

 

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
    $(document).ready(function() {
        $('#search-form').on('submit', function(event) {  //search-form이란 id를 가진 form안에 있는 'submit' 버튼이 눌러졌을 때
            event.preventDefault();
            var s_date = $('#s_date').val();  // 's_date'라는 id를 가진 input 박스의 값을 저장한다.
            var e_date = $('#e_date').val();
            var city = $('#city').val();
            var updong = $('#updong').val();
            var csrf_token = $('input[name="csrfmiddlewaretoken"]').val();
            $.ajax({
                type: 'GET',                 // ajax로 송수신의 type, 이 type에 따라 views.py에서도 연동됨. 
                url: '/filtered_estate/',    //views.py에 있는 함수가 있는 url.
                data: {
                    's_date': s_date,        //views.py의 함수에 변수로 보내 줌.
                    'e_date': e_date,
                    'city': city,
                    'updong':updong,

                    'csrfmiddlewaretoken':csrf[0].value,
                },            
                success: function(datas) {     //정상적으로 송신이 되었고, views.py에서 보내는 data를 받은 후에 행해질 작업들
                    var items=datas.items      //json으로 보내진 데이터 묶음을 개별로 분리함.
                    var s_date=datas.s_date
                    var e_date=datas.e_date
                    var city=datas.city
                    var updong=datas.updong

                    $('#search_table').empty    //json으로 받은 데이터를 넣을 테이블에 기존에 있는 값들을 비운다.
                    var tableContent = '';       //테이블에 넣을 값들을 대표한 변수 설정
                    tableContent += '<tr>';             //테이블을 비웠기 때문에 ,header를 세로 설정함.
                    tableContent += '<th>도로명</th>';
                    tableContent += '<th>도로명시군구코드</th>';
                    tableContent += '<th>법정동</th>';
                    tableContent += '<th>지번</th>';
                    tableContent += '<th>아파트</th>';
                    tableContent += '<th>전용면적</th>';
                    tableContent += '<th>거래금액</th>';
                    tableContent += '<th>년월</th>';
                    tableContent += '</tr>';    
                    
                    items.forEach(function(item) {         //json으로 받은 데이터가 두개 이상이라서 순환적으로 데이터를 넣어줌.
                        tableContent += '<tr>';
                        tableContent += '<td>' + item.도로명 + '</td>';
                        tableContent += '<td>' + item.도로명시군구코드 + '</td>';
                        tableContent += '<td>' + item.법정동 + '</td>';
                        tableContent += '<td>' + item.지번 + '</td>';
                        tableContent += '<td>' + item.아파트 + '</td>';
                        tableContent += '<td>' + item.전용면적 + '</td>';
                        tableContent += '<td>' + Number(item.거래금액).toLocaleString('en-US', {minimumFractionDigits: 0}) + '</td>';  //천원단위 표시함수 적용.
                        tableContent += '<td>' + item.년 + item.월 + '</td>';
                        tableContent += '</tr>';
                    });
                    $('#search_table').html(tableContent);  //'search_table'이란 id를 가진 테이블을 찾아서 데이터를 가진 변수를 적용함.
                },
                error: function(xhr, errmsg, err) {
                    // 에러 처리 코드
                }
            });
        });        
    });
</script>

 

 

  자바스크립트가 완성되면, 클라이언트에서 보낸 값들을 받아[ request.GET.get('') ], 그 이후에 open api를 통해 자료를 요청하여 받은 자료들을 다시  클라이언트(html)로 보내면 된다.  이 코딩은 처음 시작할 때의 'estate' 함수와거의 동일하다. 단지 다시 클라이언트로 보낼 때 json을 사용하기 때문에, 이때 보내는 데이터의 형식을 리스트[] 로 보내야한다는 차이가 있다.

   

  모듈 함수 ('filtered_estate')을 만들어 보자. 

 

def filtered_estate(request):
    # 서비스키 할당하기
    service_key = ""
    
    # 데이터 조회 인스턴스 만들기
    from PublicDataReader import TransactionPrice
    api = TransactionPrice(service_key)

    start_date=request.GET.get('s_date')   #클라이언트(html)로부터 's_date'란 값을 가져온다.
    end_date=request.GET.get('e_date')
    sigungu_name =request.GET.get('city')
    updong=request.GET.get('updong')

    # 시군구코드 조회하기
    import PublicDataReader as pdr    
    code = pdr.code_bdong()
    filtered_code = code.loc[(code['시군구명'].str.contains(str(sigungu_name)))]

    # 특정 기간 자료 조회하기
    df = api.get_data(
        property_type="아파트",
        trade_type="매매",
        sigungu_code=filtered_code['시군구코드'],
        start_year_month=start_date,
        end_year_month=end_date,
        #year_month=start_date,  # 특정 년월 자료만 조회하기
    )

    filtered_df=df[df['법정동'] == updong]

    # Json으로 보낼때는 추출한 데이터를 리스트로 변환
    filtered_data = filtered_df.to_dict(orient='records')

    datas = {
        'items': filtered_data,
        's_date':start_date,
        'e_date':end_date,
        'city':sigungu_name,
        'updong':updong,
    }

    return JsonResponse(datas, safe=False)

 

  이렇게 하면, 클라이언트 html에서 텍스트 박스에 입력한 값을 적용한 데이터가 나타나게 된다.

 

  오늘은 여기까지 하는 것으로 마치며, 여기에 추가로 적용 진행할 부분은,

 

   - 주어진 데이터에서 '아파트명'으로 실시간 필터링하는 텍스트박스를 만들어 알고싶은 아파트에 대한 정보를 바로 확인 할 수 있게 한다.

   - '시군구명' 기초 데이터를 가지고 있기 때문에, 클라이언트의 텍스트박스에 직접 '시군구명'과 '읍면동'이 리스팅되어 autocomplete이 되게 하는 것.

   - PYPI란 모듈을 사용하여 쉽게 작업을 한 부분이 있는데, 이 모듈을 사용하지 않고 직접 코딩으로 open api를 불러와서 작업을 하는 것이다.

'Django' 카테고리의 다른 글

Django_자산관리 Web Program Project_01  (0) 2023.11.07

관련글 더보기