2024년 2월 3일 토요일

Django 사용한 간단한 데쉬보드 웹 어플리케이션 개발하기

이 글은 Django 사용한 간단한 데쉬보드 웹 어플리케이션 개발 이야기를 나눔한다.

웹 어플리케이션 개발 방법은 다양하지만, 몇 년 사이에 유행하고 있는 트랜드는 마이크로 서비스 개발이 가능한 플라스크 같은 플랫폼을 사용하는 것이다. 여기서는 개발자가 애용하고 있는 파이썬 기반 Django(장고) 플랫폼을 사용해 웹 서비스 개발 방법을 알아본다.
장고를 이용하면, 파이썬의 다양한 라이브러리를 사용한 웹 앱을 손쉽게 개발할 수 있다. 장고보다 경량의 플랫폼인 플라스크 사용법은 다음 링크를 참고한다.
이 글은 다음 레퍼런스를 참고한다.
이 글의 소스코드는 다음 링크를 참고한다. 

개발 환경 준비
다음과 같이 개발 환경을 준비한다.
  1. 데이터베이스 설치: Django 설치시 sqlite db가 설치된다. 만약, 다른 DB를 사용하고 싶다면, MariaDB, MySQL, PostgreDB 등을 설치한다. 
  2. 데이터베이스 커넥터 설치: pip install mysqlclient 명령으로 커넥터 드라이버 설치한다.
  3. 장고 설치: pip install Django
제대로 설치되었다면, 다음 코드를 입력해 실행한다. 정상동작하면 성공한 것이다. 
import django
print(django.get_version())

데쉬보드 개발해보기
터미널에서 다음 명령을 실행해본다.
django-admin startproject monitoring
cd monitoring
python manage.py runserver

이제, The install worked successfully! Congratulations!를 클릭해 본다. 다음과 같이 웹 앱이 실행되면 성공한 것이다. 

터미널에 다음 같이 실행한다. 이 결과로 dashboard 앱 코드가 자동생성될 것이다. 
python manage.py startapp dashboard

자동생성된 앱 코드 소스 파일

각 파일 역할은 다음과 같다. 
  • __init__.py : 이 앱에 필요한 파이썬 패키지를 초기화하고, 임포트함
  • admin.py : 장고 관리자 페이지를 위한 설정
  • apps.py : app 설정 
  • models.py : 장고 ORM(Object Relationship Mapping)을 위한 클래스 정의
  • tests.py : 테스트 클래스 정의
  • views.py : 데이터가 웹 템플릿에 의해 보여지는 방식을 정의
생성된 웹 앱을 등록하기 위해, monitoring/settings.py을 다음과 같이 편집한다. 
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'dashboard'
]
편집 화면 일부

views.py에 데쉬보드가 보여질 방법을 코딩한다. 이 파일을 편집해 다음과 같이 코딩한다. 
from django.http import JsonResponse
from django.shortcuts import render
from dashboard.models import Order
from django.core import serializers

def dashboard(request):   // 이 함수는 사용자가 URL 입력 시 호출됨
    return render(request, 'dashboard.html', {})  // 이때 HTML 템플릿을 사용해 렌더링

def order_data(request):  // HTML 렌더링 시 전달될 DB의 데이터는 JSON 형태로 변환 리턴
    dataset = Order.objects.all()
    data = serializers.serialize('json', dataset)
    return JsonResponse(data, safe=False)

여기서, 데쉬보드에 렌더링될 템플릿 HTML파일을 리턴하는 dashboard..()함수, 보여질 데이터를 준비하는 pivot...() 함수를 준비해 놓았다. 참고로, 아직 구현되지 않은 HTML과 Order 모델은 이후 작업될 것이다. 

URL-함수 맵핑
앞서 정의된 함수를 사용자 URL 입력 시 실행되도록 맵핑해야 한다. 
이를 위해, monitoring/urls.py를 다음과 같이 편집한다. 
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('dashboard/', include('dashboard.urls'))
]

위 코드에서 include에 urls.py를 사용하므로, 이 파일을 코딩해야 한다. dashboard/urls.py 파일을 다음같이 편집한다. 앞서 정의된 함수와 URL이 연결된 것을 알 수 있다.
from django.urls import path
from . import views

urlpatterns = [
    path('', views.dashboard, name='dashboard'),
    path('data', views.order_data, name='order_data'),
]

모델 개발
이제 보여줄 데이터를 가지고 있는 모델을 코딩한다. 여기서는 가벼운 SQLite를 데이터베이스로 사용한다. 
from django.db import models

class Order(models.Model):
    product_category = models.CharField(max_length=20)
    payment_method = models.CharField(max_length=50)
    shipping_cost = models.CharField(max_length=50)
    unit_price = models.DecimalField(max_digits=5, decimal_places=2)

이제 정의된 모델 클래스를 데이터베이스 테이블로 생성해줘야 데이터를 저장할 수 있다. 이 처리를 위해, 다음 명령으로 마이그레이션을 한다.
python manage.py makemigrations dashboard

결과, 다음과 같이 자동으로 지정 폴더의 model을 읽어 ORM처리 하도록 설정된다. 

다음 명령으로 DB 테이블을 만든다.
python manage.py migrate dashboard
명령 실행 결과
테이블 생성 후 Sqlite DB 파일

DB 테이블이 생성되었으니, 예제로 사용할 데이터를 INSERT해보자. 다음 명령을 실행한다.
python manage.py shell

DB를 조작할 수 있는 터미널이 실행될 것이다. 여기서 파이썬 코드를 실행할 수 있다. 다음을 입력한다. 
from dashboard.models import Order

o1 = Order(
 product_category='Books',
 payment_method='Credit Card',
 shipping_cost=39,
 unit_price=59
)

o1.save()

이런 방식으로 원하는 만큼 데이터 레코드를 INSERT할 수 있다.
데이터 생성 모습

참고로, 다음 명령으로 생성된 데이터를 리스트할 수 있다. 셀의 상세 기능은 여기를 참고한다. 
for u in Order.objects.all():
    print(u)
    dic = u.__dict__
    for f, v in dic.items():
        print(f'{f}: {v}')
데이터 리스트 모습

데쉬보드 UI와 데이터 연결
이제 준비된 데이터를 데쉬보드 UI에 연결해야 한다. 

웹에서 UI 처리는 크게 '요청-응답' 방식, 비동기 요청 방식(AJAX)이 있다. 여기서는 AJAX 방식을 사용한다. 이를 위해 jQuery $.ajax 함수를 사용하였다. 관련된 상세 사용법은 아래 링크를 참고한다. 
templates/dashboard...html 파일을 다음과 같이 편집한다. 데쉬보드는 Flexmonster UI로 만든 테이블, 원 차트 두개로 구성된다. 
<script>
function processData(dataset) {
    var result = []
    dataset = JSON.parse(dataset);
    dataset.forEach(item => result.push(item.fields));
    return result;
}
$.ajax({   // 비동기 jQuery 호출. 데이터는 DB에 미리 준비됨. URL HTML 렌더링은 비동기. 
    url: $("#pivot-table-container").attr("data-url"),
    dataType: 'json',
    success: function(data) {
        new Flexmonster({
            container: "#pivot-table-container",
            componentFolder: "https://cdn.flexmonster.com/",
            width: "100%",
            height: 430,
            toolbar: true,
            report: {
                dataSource: {
                    type: "json",
                    data: processData(data)
                },
                slice: {}
            }
        });
        new Flexmonster({
            container: "#pivot-chart-container",
            componentFolder: "https://cdn.flexmonster.com/",
            width: "100%",
            height: 430,
            //toolbar: true,
            report: {
                dataSource: {
                    type: "json",
                    data: processData(data)
                },
                slice: {},
                "options": {
                    "viewType": "charts",
                    "chart": {
                        "type": "pie"
                    }
                }
            }
        });
    }
});
</script>

여기서 사용된 데쉬보드 UI인 Flexmonster는 ajax모드에서 pivot-table-container ID를 가진 div에 임베딩되도록 설정되어 있다.  

여기서, processData는 URL질의 결과 리턴되는 JSON 텍스트를 파싱해, result 리스트에 각 아이템을 추가하는 역할을 한다. 이 함수는 Flexmonster란 데쉬보드 UI의 report의 datasource에 지정되어, UI와 데이터를 연결하는 역할을 한다. 

Flexmonster 데쉬보드는 데이터소스 속성이 보여지는 방식을 설정할 수 있다. 다음과 같이 편집한다. 
dataSource: {
type: "json",
data: processData(data),
mapping: {
"product_category": {
"caption": "Product Category",
"type": "string"
},
"payment_method": {
"caption": "Payment Method",
"type": "string"
},
"shipping_cost": {
"caption": "Shipping Cost",
"type": "number"
},
"unit_price": {
"caption": "Unit Price",
"type": "number"
}
}
},

이제 다음 명령으로 개발한 웹 앱을 실행해 본다. 
python manage.py runserver

URL은 Dashboard를 클릭한다. 다음과 같이 보여지면 성공한 것이다. 
장고로 개발된 웹 앱 실행 결과

맵 연동 
이제 맵과 연동해 본다. 다음은 리플릿과 Plotly을 이용한 간단한 장고 웹 앱 실행 결과이다.



코드 디버깅
장고로 개발한 코드를 디버깅할 수 있으면, 실행 상태에서 변수, 콜 스택 등을 쉽게 확인할 수 있다. 우선, 디버깅 버튼의 launch.json 생성 버튼을 클릭해, .vscode 폴더에 launch.json을 생성한다.
Debug의 create a launch.json 버튼

다음과 같이 launch.json를 수정한다. 보다시피, 디버깅할 programd의 args를 설정해 두었다. 본 실습에는 chrome대신 edge를 사용하였기에, 두번째 설정은 msedge로 타입을 지정하였다.
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Django",
            "type": "debugpy",
            "request": "launch",
            "program": "${workspaceFolder}\\manage.py",
            "args": [
                "runserver",
                "--noreload"
            ], 
            "django": true,
            "justMyCode": true
        }, 
        {
            "name": "Edge",
            "type": "msedge",
            "request": "launch",
            "url": "http://localhost:8000",
            "webRoot": "${workspaceFolder}"        
        }            
    ]
}

생성된 launch.json 파일

이제 manager.py를 선택하고 디버깅 버튼을 클릭하면 다음과 같이, 코드를 디버그할 수 있다.
장고 웹 앱 디버깅 모습

로그는 settings.py에 다음 LOGGING 사전을 추가하고, 원하는 코드에 사용하면 된다. 
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "console": {"class": "logging.StreamHandler"},
    },
    "loggers": {
        "django": {
            "handlers": ["console"],
            "level": "INFO",
        },
    }
}

코드는 다음과 같다. 
import logging
import logging.config
logger = logging.getLogger('django')

logger.info('here goes your message')

def your_func():
    logging.config.fileConfig('logging.conf')
    logger = logging.getLogger('applog')

    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')

좀 더 상세한 디버깅 방법은 다음을 참고한다.

마무리
이 글을 통해, 간단히 장고로 만든 앱 앱을 코딩하고 실행해 보았다. 이와 같은 방식으로 다양한 웹 앱을 개발할 수 있을 것이다. 

레퍼런스
부록: Mongo 데이터베이스 연결
일반적으로, Django가 지원하는 database는 sqlite, mysql, postgresql 이다. 그러므로, mongo database를 settings.py에서 설정한 후 실행해보면, 다음과 같이 에러가 발생할 수 있다.

django.core.exceptions.ImproperlyConfigured: 'django_mongodb_engine' isn't an available database backend.
Try using 'django.db.backends.XXX', where XXX is one of:
u'base', u'mysql', u'oracle', u'postgresql_psycopg2', u'sqlite3'
Error was: cannot import name BaseDatabaseFeatures

이 경우, 다음과 같이 패키지를 설치한다. djongo는 mongodb와 django를 연결해 준다. 
pip install djongo
pip install pytz


댓글 없음:

댓글 쓰기