장고 웹 애플리케이션에서 Matplotlib을 이용하여 데이터 시각화하기
django-admin startproject SALES
생성 후 프로젝트 구조는 아래와 같다.
├── db.sqlite3
├── manage.py
├── SALES
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── static
│ ├── book.jpg
│ ├── bootstrap-5.0.0-beta1-dist
│ │ ├── css
│ │ │ ├── bootstrap.css
│ │ │ ├── bootstrap.css.map
│ │ │ ├── bootstrap-grid.css
│ ├── style.css
python manage.py startapp sales
settings.py
에 앱 추가 & static 파일 설정INSTALLED_APPS = [
'sales',
'crispy_forms' # 스타일링 하기 위한 앱
]
CRISPY_TEMPLATE_PACK = 'bootstrap4'
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
static 파일은 /static
폴더 밑에 있음을 알려준다.
/media
폴더에 업로드된 미디어 파일을 저장한다.
urls.py
을 수정한다.from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
urlpatterns = [path('admin/', admin.site.urls)]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py
파일에 내용을 추가한다.
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
from django.utils import timezone
from sales.utils import generate_code
# Customer class to keep track of name and image
class Customer(models.Model):
name = models.CharField(max_length=120)
logo = models.ImageField(upload_to='customers')
def __str__(self):
return self.name
# SalesPerson class to keep track of the the sales person's information
class SalesPerson(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(default='No bio yet...')
avatar = models.ImageField(upload_to='avatars')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Salesperson {self.user.username}"
# Sale class to keep track of the sales information
class Sale(models.Model):
transaction_id = models.CharField(max_length=12, blank=True)
total_price = models.FloatField(blank=True, null=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
salesman = models.ForeignKey(SalesPerson, on_delete=models.CASCADE)
created = models.DateTimeField(blank=True)
updated = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
if self.transaction_id == "":
self.transaction_id = generate_code()
if self.created is None:
self.created = timezone.now()
return super().save(*args, **kwargs)
def __str__(self):
return f"Sales for the amount of Kshs {self.total_price}"
Sale
클래스를 이용하여 나타낸다save
메소드를 오버라이드하여 사용한다.import uuid
def generate_code():
return str(uuid.uuid4()).replace('-', '').upper()[:12]
12자리의 랜덤 알파벳 코드를 반환한다.
admin.py
파일에 코드를 작성한다from django.contrib import admin
from .models import Customer, Sale, SalesPerson
# Register your models here.
admin.sites.register(Customer)
admin.sites.register(Sale)
admin.sites.register(SalesPerson)
superuser
를 생성한다.python manage.py createsuperuser
관리자 계정을 생성한 후 관리자 페이지에 들어가보면 모델들이 등록되어 있다.
유저가 특정 데이터를 찾을 수 있도록 검색하는 폼을 만들어준다
date, transaction, customer address, total price를 기반으로 정보를 필터링한다.
forms.py
파일을 만들고 폼 필드를 정의한다.
from django import forms
CHART_CHOICE = (
('#1', 'Bar Graph'),
('#2', 'Pie Chart'),
('#3', 'Line Graph')
)
RESULTS_CHOICES = (
('#1', 'Transaction'),
('#2', 'Sales Date'),
('#3', 'Customer ID'),
('#4', 'Total Price')
)
class SalesSearchForm(forms.Form):
date_from = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))
date_to = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))
chart_type = forms.ChoiceField(choices=CHART_CHOICE)
results_by = forms.ChoiceField(choices=RESULTS_CHOICES)
사용자가 날짜, 차트타입, 결과를 선택할 수 있는 폼이다.
데이터를 웹페이지에 보내기 위해서 뷰를 작성한다
views.py
파일을 수정한다.
import pandas as pd
from django.shortcuts import render
from django.views.generic import ListView
from .forms import SalesSearchForm
# Create your views here.
def sales(request):
search_form = SalesSearchForm(request.POST or None)
context = {'search_form' : search_form}
return render(request, 'sales.html', context)
sales
함수는 검색 폼을 HTML 파일에 렌더한다.
settings.py
파일의 템플릿 설정 수정하기
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
위 설정은 Django가 HTML 파일을 찾을 때 templates 라는 폴더로부터 찾도록한다.
manage.py
파일과 같은 레벨에 templates 폴더를 생성하고 HTML파일을 생성한다.
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{% static 'style.css' %}">
<link rel="stylesheet" href="{% static 'bootstrap-5.0.0-beta1-dist/css/bootstrap.css' %}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.11.8/semantic.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.11.8/semantic.min.js"></script>
<title>Report App | {% block title %} {% endblock title %}</title>
</head>
<body>
<div class="ui secondary menu">
<a class="item"><img style="height:100px;width:100px;" src="{% static 'book.jpg' %}" alt=""></a>
<a href="#" class=" active item">Home</a>
</div>
<div class="container mb-3 mt-3">
{% block content %}
{% endblock content %}
</div>
</body>
</html>
다른 파일들을 위해 사용될 베이스 HTML파일. 공통 스타일링이 정의되어 있다.
베이스 HTML 파일을 사용함으로써 같은 코드를 반복작성하지 않아도 된다. 다른 파일에서 베이스 파일을 사용하기 위해서 {% extends 'base.html' %}
를 작성하면 스타일링이 적용됨
위의 베이스 파일은 애플리케이션의 다른 루트들의 링크를 가지고 있다. HOME 루트는 데이터 표현 페이지로 네비게이트한다.
{% extends 'base.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block scripts %}
{% endblock scripts %}
{% block title %}
Home
{% endblock title %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ search_form|crispy }}
<button class="btn btn-primary mt-3" type="submit">Search</button>
</form>
{% endblock content %}
위 페이지는 검색폼을 나타낸다.
뷰가 실제로 동작하게 하기 위해서 루트를 설정해줘야한다. (url 경로 설정)
sales 앱 하위에 urls.py
파일을 새로 생성한다. 이 파일을 함수와 클래스로의 라우팅을 다룬다.
요청들은 이 파일에 의해서 처리되며 요청에 일치하는 함수와 클래스로 라우팅된다.
from django.urls import path
from . import views
urlpatterns = [
path('', views.sales, name='sales')
]
sale 앱에 대한 라우팅을 처리하기 위해서 SALE 프로젝트의 url을 설정한다
SALES/urls.py
파일을 수정한다.
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('sale.urls'))
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
뷰에 접근하기 위해서 파일을 수정한다.
<a href="{{sales_home}}" class=" active item">Home</a>