상세 컨텐츠

본문 제목

[K-DIGITAL] Django 실습과 pythonanywhere 배포(1) 웹 프로젝트

PYTHON/K-DIGITAL

by ranlan 2021. 8. 2. 17:09

본문

728x90

멋쟁이사자처럼 X K-DIGITAL Training - 08.02

 

 

파이널 프로젝트 전 마지막 수업내용은 기다리고 기다렸던 파이썬 장고

간단한 로또번호 생성 페이지부터 이미지 업로드와 머신러닝 모델 연결까지 짧은 시간이였지만 파이널프로젝트를 해낼 수 있을 정도까지는 배울 수 있었다.

마지막으로 파이썬 애니웨어에 빠르게 배포하는 법까지!

 

수업시간에 배포한 웹 서비스는 openCV를 이용한 얼굴 감지 서비스이지만 중요한것은 openCV가 아니라 Django 이기에

장고와 파이썬애니웨어 배포를 중심으로 포스팅 할 예정

 

 

[GITHUB] https://github.com/ijo0r98/django-opencv

 

GitHub - ijo0r98/django-opencv: [K-DIGITAL] openCV & Django 실습

[K-DIGITAL] openCV & Django 실습. Contribute to ijo0r98/django-opencv development by creating an account on GitHub.

github.com


 

 

가상환경부터 장고 프로젝트 생성까지

# 장고를 위한 가상환경은 이곳에 둘 예정
mkdir work_django
cd work_django

# 가상환경을 생성할 폴더
mkdir django_mldl
cd django_mldl

가상환경 생성 및 라이브러리 설치

# 가상환경 관리 라이브러리 
pip install virtualenv==16.7.7 

# 가상환경 생성
virtualenv django_env 

# 가상환경 실행
django_env\Scripts\activate

# 가상환경 종료
deactivate

 

장고 라이브러리 설치

pip install django==2.2.6

pip freeze # 현재 설치된 라이브러리 리스트 검토

장고 프로젝트 생성

django-admin startproject {project_name}

장고 app 생성

* 하나의 웹 사이트 내에 있는 기능들에 해당 (회원가입, 상품 관련 기능 등)

cd cv_project
python manage.py startapp {app_name}

 

 

프로젝트 기본 설정

 

파일 구성

* static 폴더는 collectstatic 후 생성됨

* media 폴더는 직접 생성

 

프로젝트 설정

 

▷ cv_project > settings.py

* DEBUG는 배포시 false로 설정

DEBUG = True # 배포 시 false

INSTALLED_APPS 리스트 상단에 생성한 앱 추가

INSTALLED_APPS = [
    'opencv_webapp', # 앱 추가
    'django.contrib.admin',
    'django.contrib.auth',
    ...
]

언어, 시간 설정

LANGUAGE_CODE = 'ko-kr'

TIME_ZONE = 'Asia/Seoul'

STATIC 경로 설정

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

MEDIA 경로 설정 (업로드된 이미지등의 파일을 다룰 때)

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_ROOT_URL = '.'

 

▷ cv_project > urls.py

url 권한 app에게 위임 (전체 url을 app 단위로 나눠서 관리)

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    # path(url, include('app_name.urls'))
    path('', include('opencv_webapp.urls')), # 앱에게 위임
]

 

앱 설정

▷ opencv_webapp > urls.py

위에서 위임받은 url 연결

from django.urls import path
from . import views # 같은 폴더 내의 views.py를 import
from django.conf import settings
from django.conf.urls.static import static

app_name = 'opencv_webapp' # 프로젝트 설정에서 app name으로 url 권한 위임

urlpatterns = [
]

# MEDIA
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

 

 

URLS

▷ cv_project(project) > opencv_webapp(app) > urls.py

path(url, views.function, name='url_name') url과 views의 함수 매핑

* 보통 url, views 함수, url name은 모두 일치하도록 설정

urlpatterns = [
    path('', views.index, name='index'),
    path('simple_upload/', views.simple_upload, name='simple_upload'),
    path('detect_face/', views.detect_face, name='detect_face'),
]

 

 

MODELS & FORMS

▷ cv_project(project) > opencv_webapp(app) > models.py

python Django ORM, 데이터베이스에 매핑될 테이블 설계

from django.db import models

# Create your models here.

class ImageUploadModel(models.Model):

    description = models.CharField(max_length=255, blank=True)
    document = models.ImageField(upload_to='images/%Y/%m/%d')
    uploaded_at = models.DateTimeField(auto_now_add=True)

- blank=True : 빈 값으로 저장 허용 (views.py에서 활용한 .is_valid() 함수가 검증 진행 시)
- upload_to : 저장될 파일의 경로를 지정 (ex. ‘images/2020/02/21/image.jpg’)
- auto_now_add : 등록 시, 자동으로 저장 시간을 현재 시간으로 세팅
- auto_now : 수정 시, 저장될 때마다 현재 시간으로 갱신

 

▷ cv_project(project) > opencv_webapp(app) > forms.py

위에서 생성한 모델 기반으로 사용자에게 입력받을 폼 생성

from django import forms
from .models import ImageUploadModel

# simple upload form
class SimpleUploadForm(forms.Form):
    title = forms.CharField(max_length=50)
    image = forms.ImageField() # file field + image

# description 추가
class ImageUploadForm(forms.ModelForm):
    class Meta:
        model = ImageUploadModel
        fields = ('description', 'document',)

 

 

VIEWS 

url 매핑 시 작성했던 함수들을 구현하여 사용자에게 보여질 화면 매핑

 

request 타입 확인

request.method # GET / POST

request에 담긴 post 데이터 확인 - input 태그의 name이 key, 입력받은 값이 value인 dict 형태

request.POST['name'] # <input name="name">

제출된 파일의 원본 확인

request.FILES # <MultiValueDict: {'image': [<InMemoryUploadedFile: ses.jpg (image/jpeg)>]}>

html render

render(request, app_name/.html, data)

 

▷ cv_project(project) > opencv_webapp(app) > views.py

simple_upload : 단순 이미지 파일 업로드

from django.shortcuts import render, redirect
from .forms import SimpleUploadForm, ImageUploadForm
from django.core.files.storage import FileSystemStorage
from django.conf import settings

def simple_upload(request):

    if request.method == 'POST': # POST request
        form = SimpleUploadForm(request.POST, request.FILES)
        
        if form.is_valid():
            myfile = request.FILES['image'] # 제출된 이미지 객체(image.jpg)

            # DB 사용하지 않을 때
            fs = FileSystemStorage()
            filename = fs.save(myfile.name, myfile) # 이미지 이름과 저장된 파일 객체 반환
            uploaded_file_url = fs.url(filename) # '/media/image.jpg'

            context = {'form': form, 'uploaded_file_url': uploaded_file_url}
            return render(request, 'opencv_webapp/simple_upload.html', context)

    else: # GET request
        form = SimpleUploadForm()
        context = {'form': form}
        return render(request, 'opencv_webapp/simple_upload.html', context) # input & label tag

detect_face: 업로드한 이미지에서 opencv를 활용하여 얼굴과 눈의 위치 찾기

from django.shortcuts import render, redirect
from .forms import SimpleUploadForm, ImageUploadForm
from django.core.files.storage import FileSystemStorage
from django.conf import settings

from .cv_functions import cv_detect_face

def detect_face(request):

    if request.method == 'POST': # POST request
        form = ImageUploadForm(request.POST, request.FILES)

        if form.is_valid():
            post = form.save(commit=False)
            ###
            # 실제로 저장하기 전 필요한 작업을 추가하여 변경, 추가 가능
            ###
            post.save() # DB에 실제로 form 객체('form')에 채워져 있는 데이터를 저장

            imageURL = settings.MEDIA_URL + form.instance.document.name
            # 실제로 db에 저장되어있는 경로 '/media/images/2021/07/30/image.jpg'
            
            cv_detect_face(settings.MEDIA_ROOT_URL + imageURL) # machine learning

            return render(request, 'opencv_webapp/detect_face.html', {'form':form, 'post':post})

    else:
        form = ImageUploadForm() # GET reuest
        return render(request, 'opencv_webapp/detect_face.html', {'form':form})

 

▷ cv_project(project) > media > 모델

이미 학습된 모델 제공 https://github.com/opencv/opencv/tree/master/data/haarcascades

 

GitHub - opencv/opencv: Open Source Computer Vision Library

Open Source Computer Vision Library. Contribute to opencv/opencv development by creating an account on GitHub.

github.com

 

▷ cv_project(project) > opencv_webapp(app) > cv_functions.py

openCV 이용한 얼굴과 눈 탐지

from django.conf import settings
import numpy as np
import cv2

def cv_detect_face(path): # ./media/images/2021/07/30/image.jpg'
    img = cv2.imread(path, 1) # image read

    if (type(img) is np.ndarray):
        print(img.shape) # 세로, 가로, 채널

        # image resize
        resize_needed = False
        if img.shape[1] > 640: 
            resize_needed = True
            new_w = img.shape[1] * (640.0 / img.shape[1]) 
            new_h = img.shape[0] * (640.0 / img.shape[1]) 
        elif img.shape[0] > 480: 
            resized_needed = True
            new_w = img.shape[1] * (480.0 / img.shape[0])
            new_h = img.shape[0] * (480.0 / img.shape[0])
        if resize_needed == True:
            img = cv2.resize(img, (int(new_w), int(new_h)))

        # Haar-based Cascade Classifier : AdaBoost 기반 머신러닝 물체 인식 모델
        baseUrl = settings.MEDIA_ROOT_URL + settings.MEDIA_URL # '.' + '/media/'

        face_cascade = cv2.CascadeClassifier(baseUrl + 'haarcascade_frontalface_default.xml')
        eye_cascade = cv2.CascadeClassifier(baseUrl + 'haarcascade_eye.xml')

        # 흑백 이미지로 변경 -> 차원 수 감소
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)

        # 얼굴 사각형 좌표
        for (x, y, w, h) in faces:
           cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
           roi_gray = gray[y:y+h, x:x+w]
           roi_color = img[y:y+h, x:x+w]

           # 눈의 위치
           eyes = eye_cascade.detectMultiScale(roi_gray)
           for (ex, ey, ew, eh) in eyes:
               cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)

        cv2.imwrite(path, img) # cv에서 만든 이미지로 바꿈

    else:
        print('Error occurred within cv_detect_face!')
        print(path)

 

 

TEMPLATES > .HTML

collectstatic 이후 생기는 static 폴더의 css 적용

<link rel='stylesheet', href="{% static 'cv_project/css/styles.css' %}">

 

 

▷ cv_project(project) > opencv_webapp(app) > templates > opencv_webapp(app_name) > simple_upload.html

forms.py에서 등록한 폼 자동 생성

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }} <!--p태그로 자동으로 묶어줌-->
    <button type="submit">Upload</button>
</form>

업로드 후 저장된 이미지 확인

{% if uploaded_file_url %}
    <a>업로드 확인👇🏻</a>
    <img src="{{ uploaded_file_url }}">
    <p>Uploaded file @ : <a href="{{ uploaded_file_url }}">{{ uploaded_file_url }}</a></p>
{% endif %}

링크 연결 - urls.py에서 등록한 url name

# opencv_webapp > urls.py
path('', views.index, name='index')
<p><a href="{% url 'opencv_webapp:index' %}">Return to home</a></p>

 

▷ cv_project(project) > opencv_webapp(app) > templates > opencv_webapp(app_name) > detect_face.html

이미지 업로드 폼

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <a style="color:red;">얼굴을 감지할 이미지 선택 후 upload를 눌러주세요</a>
    <button type="submit">Upload</button>
</form>

얼굴 감지 결과 확인

{% if post %}
    <a>결과 확인👇🏻</a>
    <img src="{{ post.document.url }}">
    <p>Uploaded file @ : <a href="{{ post.document.url }}">{{ post.document }}</a></p>
{% endif}

 

 

COLLECTSTATIC & MIGRATE

데이터베이스 설계 적용

- 마이그레이션 파일 생성 : 모델을 변경 혹은 생성한 변경사항을 마이그레이션으로 저장하고자함

python manage.py makemigrations

 

- 마이그레이션 적용 : 모델의 변경사항 저장 (*모델 수정 시)

python manage.py migrate

 

서버 시작

* 종료는 cmd창에서 ctrl+c (window)

python manage.py runserver
728x90

관련글 더보기

댓글 영역