Django

Docker 활용한 django 예제

개요

  • Docker에서 django 개발환경 만들기
  • 간단한 웹개발 실습

참고자료

실습사전조건

  • 가상환경으로 Ubuntu 24.04 LTS
  • make : 소스코드를 컴파일할 때 사용하는 자동 빌드 도구이다.
  • build-essential : C/C++ 컴파일에 필요한 기본 컴파일 도구 모음이다.
  • libssl-dev : SSL/TLS 통신을 위한 OpenSSL 라이브러리 개발 헤더이다.
  • zlib1g-dev : 압축 알고리즘용 zlib 라이브러리 개발 파일이다.
  • libbz2-dev : bzip2 압축 알고리즘용 개발 라이브러리이다.
  • libreadline-dev : 터미널에서 편리한 입력을 가능하게 하는 readline 개발 라이브러리이다.
  • libsqlite3-dev : SQLite 데이터베이스 개발에 필요한 라이브러리이다.
  • wget : 파일을 HTTP, HTTPS, FTP로 다운로드할 수 있는 명령줄 도구이다.
  • curl : 다양한 프로토콜로 데이터를 송수신할 수 있는 명령줄 도구이다.
  • llvm : C/C++ 등의 언어를 위한 컴파일러 인프라 구조이다.
  • libncurses5-dev : 터미널 기반 UI(텍스트 기반 사용자 인터페이스)를 만들기 위한 ncurses 라이브러리의 개발 파일이다.
  • xz-utils : .xz 형식의 압축을 처리할 수 있는 도구이다.
  • tk-dev : GUI 애플리케이션을 만들 때 사용하는 Tk GUI 툴킷 개발 파일이다.
  • libxml2-dev : XML 파싱 및 처리 기능을 제공하는 libxml2의 개발 헤더 및 라이브러리이다.
  • libxmlsec1-dev : XML 디지털 서명 및 암호화를 위한 libxmlsec1의 개발 라이브러리이다.
  • libffi-dev : 외부 함수 호출을 위한 외부 함수 인터페이스 개발 라이브러리이다.
  • liblzma-dev : LZMA 압축 알고리즘을 위한 개발 라이브러리이다.
  • python3-openssl : 파이썬에서 OpenSSL을 사용할 수 있도록 하는 패키지이다.
  • git : 분산 버전 관리 시스템으로, 소스코드 형상 관리를 도와준다.
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev python3-openssl git

pyenv 설치

  • 다음 명령어로 실행한다.
$ curl https://pyenv.run | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   270  100   270    0     0    404      0 --:--:-- --:--:-- --:--:--   404
Cloning into '/home/evanjjh/.pyenv'...
remote: Enumerating objects: 1365, done.
remote: Counting objects: 100% (1365/1365), done.
remote: Compressing objects: 100% (725/725), done.
remote: Total 1365 (delta 826), reused 806 (delta 507), pack-reused 0 (from 0)
Receiving objects: 100% (1365/1365), 1.14 MiB | 7.48 MiB/s, done.
Resolving deltas: 100% (826/826), done.
Cloning into '/home/evanjjh/.pyenv/plugins/pyenv-doctor'...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 11 (delta 1), reused 5 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (11/11), 38.72 KiB | 1.68 MiB/s, done.
Resolving deltas: 100% (1/1), done.
Cloning into '/home/evanjjh/.pyenv/plugins/pyenv-update'...
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 10 (delta 1), reused 5 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (10/10), done.
Resolving deltas: 100% (1/1), done.
Cloning into '/home/evanjjh/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 64, done.
remote: Counting objects: 100% (64/64), done.
remote: Compressing objects: 100% (57/57), done.
remote: Total 64 (delta 10), reused 23 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (64/64), 43.08 KiB | 2.15 MiB/s, done.
Resolving deltas: 100% (10/10), done.

WARNING: seems you still have not added 'pyenv' to the load path.

# Load pyenv automatically by appending
# the following to 
# ~/.bash_profile if it exists, otherwise ~/.profile (for login shells)
# and ~/.bashrc (for interactive shells) :

export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init - bash)"

# Restart your shell for the changes to take effect.

# Load pyenv-virtualenv automatically by adding
# the following to ~/.bashrc:

eval "$(pyenv virtualenv-init -)"

.bashrc 파일 설정

  • 먼저 vim을 설치한다.
sudo apt-get update
sudo apt-get install -y vim
  • .bashrc 파일을 연다
vi ~/.bashrc
  • 파일을 열면 다양한 환경변수 설정 코드가 들어 있다.

image.png

django-web on GCE

개요

  • django-web을 GCE에 설치 및 배포를 간단하게 진행하도록 한다.

사전준비

  • Google Cloud Platform 회원가입은 미리 진행했고, GCE 인스턴스를 생성할 줄 아는 상태임을 전제로 한다.
  • Miniconda 설치가 끝난 상황임을 가정한다.
  • Miniconda 설치
mkdir -p ~/miniconda3
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
rm -rf ~/miniconda3/miniconda.sh
  • 설치 후, 새로 설치한 미니콘다를 초기화합니다. 다음 명령은 bash 및 zsh 셸을 초기화
~/miniconda3/bin/conda init bash
~/miniconda3/bin/conda init zsh

django on GCE

  • GCE Shell에서 django를 설치한다.
pip install django
  • django의 버전을 확인한다.
django-admin --version
5.0.4
  • project 명령어를 입력한다.
django-admin startproject mysite
  • 서버를 실행해본다.
    • 경로를 mysite에 이동 시킨 후 아래 명령어를 실행한다.
$ python manage.py makemigrations
$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
$ python manage.py runserver
...

April 18, 2024 - 05:13:47
Django version 5.0.4, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Untitled

django tutorial - pyburger 3

공지

  • 멀티캠퍼스 수업 보조자료로 활용하기 위해 아래 교재 내용을 발췌하였음을 알립니다.

Untitled

Github에서 프로젝트 내려받기

Untitled

  • 다음 명령어를 실행하여 Local의 적당한 곳에서 다운로드 받는다.

폴더 수정

  • .DS_Store 파일은 삭제한다
  • 폴더명은 pyburger로 변경한다.

Untitled

VS Code로 폴더 열기

  • 아래와 같이 VS Code로 pyburger 폴더를 연다.

Untitled

프로젝트 설정

  • 가상환경을 설정하고 django를 설치한다.
$ virtualenv venv
$ source venv/Scripts/activate
(venv) $ pip install 'django<5'

첫번째 확인사항

  • runserver를 실행하여 정상적으로 작동하는지 확인한다.
(venv) $ python manage.py runserver

Untitled

django tutorial - pyburger 2

공지

  • 멀티캠퍼스 수업 보조자료로 활용하기 위해 아래 교재 내용을 발췌하였음을 알립니다.

Untitled

별도의 app 추가

  • application을 생성하는 명령어를 활용하여 app을 생성한다.
python manage.py startapp burgers
  • 트리 구조는 다음과 같다.
$ tree -L 2
.
|-- burgers
|   |-- __init__.py
|   |-- admin.py
|   |-- apps.py
|   |-- migrations
|   |-- models.py
|   |-- tests.py
|   `-- views.py
|-- config
|   |-- __init__.py
|   |-- __pycache__
|   |-- asgi.py
|   |-- settings.py
|   |-- urls.py
|   |-- views.py
|   `-- wsgi.py
|-- db.sqlite3
|-- manage.py
|-- templates
|   |-- burger_list.html
|   `-- main.html
`-- templates.zip

새 Application을 Django 등록

  • confing/settings.py 에서 INSTALLED_APPS 리스트에 아래와 같이 추가
INSTALLED_APPS = [
    "burgers", 
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]

Model 클래스 구현

  • Model 클래스 정의하기 전에 햄버거를 나타낼 수 있는 정보를 몇 가지 정리한다.
    • 이름
    • 가격
    • 칼로리
  • burgers/models.py 에서 아래와 같이 코드를 생성한다.
from django.db import models

# Create your models here.
class Burger(models.Model):
    name  = models.CharField(max_length=20)
    price = models.IntegerField(default=0)
    calories = models.IntegerField(default=0)

데이터베이스 마이그레이션

  • 새로운 테이블을 만들기 위해 다음 명령어를 사용한다.
python manage.py migrate

Untitled

django tutorial - pyburger 1

Django Pyburger - 1, 맛보기

공지

  • 멀티캠퍼스 수업 보조자료로 활용하기 위해 아래 교재 내용을 발췌하였음을 알립니다.

Untitled

Django 설치

  • 터미널에서 django를 설치한다.
pip install 'django<5'

Untitled

Django 버전 확인

  • 터미널에서 Django의 버전을 확인한다.
django-admin --version
4.2.9

Django 프로젝트 생성

  • 다음 명령어를 실행하여 django 프로젝트를 생성한다.
  • djang-admin은 터미널에서 실행할 수 있는 프로그램이며, django 프로젝트를 관리하는 여러 기능들을 가지고 있음
  • startproject는 django 프로젝트의 기반 구조를 만드는 기능
django-admin startproject config .
$ tree -L 2
.
|-- README.md
|-- config
|   |-- __init__.py
|   |-- asgi.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
|-- manage.py
`-- venv
    |-- Lib
    |-- Scripts
    `-- pyvenv.cfg

4 directories, 8 files

개발용 서버 동작 확인

  • 명령어는 다음과 같다.
    • 이 때 manage.py 가 있는 프로젝트 경로에서 실행해야 한다.
python manage.py runserver

Untitled

Django - ExcelCalCulator_7

개요

  • Django 한 그릇 뚝딱 교재의 내용에서 멀티캠퍼스 강의에 맞게 일부 수정함
  • 2019년 버전이고 현재는 2023년이기 때문에 소스코드 변경 사항이 필요할 거 같아서 글을 남김

교재 홍보

Untitled

Step 01 - 이전 글

Step 02 - 프로젝트 완성하기

  • 지금까지 구현한 기능과 미완료된 기능을 확인한다.

Untitled

Step 03 - 로그인 실패 시 보이는 화면을 구현

  • 우선 사용자가 로그인 실패 시, 보이는 화면으로 구현한다.

Django - ExcelCalCulator_6

개요

  • Django 한 그릇 뚝딱 교재의 내용에서 멀티캠퍼스 강의에 맞게 일부 수정함
  • 2019년 버전이고 현재는 2023년이기 때문에 소스코드 변경 사항이 필요할 거 같아서 글을 남김

교재 홍보

Untitled

Step 01 - 이전 글

Step 02 - 프로젝트 완성하기

  • 지금까지 구현한 기능과 미완료된 기능을 확인한다.

Untitled

Step 03 - 엑셀 결과 화면 출력 위한 세션값 저장

  • 우선 calculate 함수의 마지막에 엑셀 결과 화면으로 데이터와 함께 url을 이동시켜본다.
  • views.py에 코드를 추가한다.
  • 파일 경로 : ExcelCalculate > calculate > views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
import pandas as pd

# Create your views here.
def calculate(request):
    file = request.FILES['fileInput']
    print("# 사용자가 등록한 파일의 이름: ", file)
    df = pd.read_excel(file, sheet_name="Sheet1", header=0)
    print(df.head())
    # grade별 value 리스트 만들기
    grade_dic = {}
    total_row_num = len(df.index)
    for i in range(total_row_num):
        data = df.loc[i, :]
        if not data.grade in grade_dic.keys():
            grade_dic[data.grade] = [data.value]
        else:
            grade_dic[data.grade].append(data.value)

    # print(grade_dic)
    # grade별 최솟값 최댓값 평균값 구하기
    grade_calculate_dic = {}
    for key in grade_dic.keys():
        grade_calculate_dic[key] = {}
        grade_calculate_dic[key]['min'] = min(grade_dic[key])
        grade_calculate_dic[key]['max'] = max(grade_dic[key])
        grade_calculate_dic[key]['avg'] = float(sum(grade_dic[key])) / len(grade_dic[key])

    # 결과 출력
    grade_list = list(grade_calculate_dic.keys())
    grade_list.sort()
    for key in grade_list:
        print("# grade: ", key)
        print("min:", grade_calculate_dic[key]['min'], end="")
        print("/ max:", grade_calculate_dic[key]['max'], end="")
        print("/ avg:", grade_calculate_dic[key]['avg'], end="\n\n")

    # 아래 코드와 동일
    result = df.groupby('grade')['value'].agg(["min", "max", "mean"])
    print(result)

    # 이메일 주소 도메인별 인원 구하기
    email_domain_dic = {}
    for i in range(total_row_num):
        data = df.loc[i, :]
        email_domain = data['email'].split("@")[1]
        if not email_domain in email_domain_dic.keys():
            email_domain_dic[email_domain] = 1
        else:
            email_domain_dic[email_domain] += 1
    print("## EMAIL 도메인별 사용 인원")
    for key in email_domain_dic.keys():
        print("#", key, ": ", email_domain_dic[key], "명")

    df['domain'] = df['email'].apply(lambda x : x.split("@")[1])
    result2 = df.groupby('domain')['value'].agg("count").sort_values(ascending=False)
    print(result2)

    # 세션 추가
    grade_calculate_dic_to_session = {}
    for key in grade_list:
        grade_calculate_dic_to_session[int(key)] = {}
        grade_calculate_dic_to_session[int(key)]['max'] = float(grade_calculate_dic[key]['max'])
        grade_calculate_dic_to_session[int(key)]['avg'] = float(grade_calculate_dic[key]['avg'])
        grade_calculate_dic_to_session[int(key)]['min'] = float(grade_calculate_dic[key]['min'])
     request.session['grade_calculate_dic'] = grade_calculate_dic_to_session
      request.session['email_domain_dic'] = email_domain_dic

    # return HttpResponse("calculate, calculate function!")
    return redirect('/result')
  • 세션 추가 이하의 코드를 살펴보면 다음과 같다.
    • pandas의 기본 자료형은 numpy 기반인데, 장고에서는 numpy 기반의 자료형이 아닌 파이썬 기본 자료형으로 변환해주어야 한다.
    • 따라서, 정수형 숫자로 된 것으로 int형으로 유리수 형태의 숫자를 float형으로 자료를 변환한다.
    • 형 변환을 하고 나서 해당 값들을 결과 화면에서 사용하려고 세션에 저장해준다.
    • 마지막으로 redirect(”/result”) 로 처리하였다.
      • 결과 화면을 관리하는 함수는 main app에 있는 result 함수이다. 따라서, 해당 url로 갈 수 있도록 처리한 것이다.

Step 04 - result 함수 수정

  • 파일 경로 : ExcelCalculate > main > views.py

Django - ExcelCalCulator_5

개요

  • Django 한 그릇 뚝딱 교재의 내용에서 멀티캠퍼스 강의에 맞게 일부 수정함
  • 2019년 버전이고 현재는 2023년이기 때문에 소스코드 변경 사항이 필요할 거 같아서 글을 남김

교재 홍보

Untitled

Step 01 - 이전 글

Step 02 - 파일 업로드 하기

  • 로그인을 통해 메인 화면으로 왔다면, 파일 업로드 기능 구현

Step 03 - 파일 업로드 기능 구현

check - 1 : index.html 구현

  • 파일 경로 : ExcelCalculate > main > templates > main > index.html
  • 파일 제출 버튼을 눌렀을 때 가려는 url을 등록한다.
  • 또한 enctype="multipart/form-data" 를 추가한다.
    • 이것을 사용해야 파일의 내용이 올바르게 전달된다.
        <div class="content">
            <div class="fileInputDiv">
                <form action="**calculate/**" method="POST" enctype="multipart/form-data">{% csrf_token %}
                    <div class="input-group">
                        하단 버튼을 통해 파일을 업로드 해주세요.(.xls 확장자의 파일만 가능합니다.)<br>
                        <input id="fileInput" name="fileInput" type="file" class="form-control">
                        <input type="submit" class="btn btn-success btn-lg" value="파일 제출">
                    </div>
                </form>
            </div>
        </div>
  • calculate/ 경로는 초기에 ExcelCalculate > ExcelCalculate > urls.py에서 이미 설정해놨다.
    • 링크 참조 :
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('email/', include('sendEmail.urls'), name="email"), 
    path('calculate/', include('calculate.urls'), name="calculate"),
    path('', include('main.urls'), name="main"),
    path("admin/", admin.site.urls),
]
  • ExcelCalcalculate > calculate > urls.py 에서도 이미 설정을 해놨다.
from django.urls import path
from . import views

urlpatterns = [
    path('', views.calculate, name="calculate_do"), 
]

check - 2 : views.py 구현

  • 파일 경로 : ExcelCalculate > calculate > views.py
  • 이 때, request.POST가 아닌 request.FILES를 이용한다.
# Create your views here.
def calculate(request):
    file = request.FILES['fileInput']
    print("# 사용자가 등록한 파일의 이름: ", file)
    return HttpResponse("calculate, calculate function!")

check - 3 : 테스트

  • 이제 data.xlsx 파일을 업로드 한다.
  • 파일 제출 버튼을 누를 시, 웹에서는 정상적으로 calculate, calculate function! 출력이 되어야 하고 터미널에서는 아래와 같이 print() 문구가 나와야 한다.

Untitled

Django - ExcelCalCulator_4

개요

  • Django 한 그릇 뚝딱 교재의 내용에서 멀티캠퍼스 강의에 맞게 일부 수정함
  • 2019년 버전이고 현재는 2023년이기 때문에 소스코드 변경 사항이 필요할 거 같아서 글을 남김

교재 홍보

Untitled

Step 01 - 이전 글

Step 02 - 로그인 기능 구현

  • 로그인된 사용자만 이용할 수 있도록 구현
  • 이 때, 현재 사용자가 로그인된 사용자인지 판단하려고 세션 사용
  • 회원 가입 통한 과정 이외에도 정상적인 로그인 과정에서도 세션 처리 진행

Step 03 - 로그인 처리 구현

check - 1 : signin.html 구현

  • 파일 경로 : ExcelCalculate > main > templates > main > signin.html
                <h3>안녕하세요. 로그인을 진행해주세요.</h3><br>
                <form action="signin/login" method="POST">{% csrf_token %}
                    <div class="input-group">

check - 2 : urls.py

  • urls.py에서도 처리해준다.

Django - ExcelCalCulator_3

개요

  • Django 한 그릇 뚝딱 교재의 내용에서 멀티캠퍼스 강의에 맞게 일부 수정함
  • 2019년 버전이고 현재는 2023년이기 때문에 소스코드 변경 사항이 필요할 거 같아서 글을 남김

교재 홍보

Untitled

Step 01 - 이전 글

Step 02 - 인증하기 구현

  • 자신의 이메일로 발송된 인증 코드를 입력한 후, “인증하기” 버튼을 누르면, main app[views.py](http://views.py) 파일에 만들어 놓은 verify 함수로 오도록 설정한다.
    • verifyCode.html url을 설정한다.
    • 파일 경로 : ExcelCalculate > main > templates > main > verifyCode.html
    • 46번 줄의 form 태그 action 값을 verify로 설정
                <h3>이메일로 전송된 메일의 인증코드를 입력해주세요.</h3><br>
                <form action="verify" method="POST">{% csrf_token %}
                    <div class="input-group">
  • 이번에는 main app > views.pyverify 함수를 구현한다.
    • 사용자가 입력한 code 값을 받아왔고, 쿠키에 저장된 code 값을 가져온다.
    • 두 값을 비교해 일치할 때는 해당 사용자의 user_validate 값을 1로 변경시켜준다.
    • user의 user_validate 값은 1로 변경시켜 준 후, 해당 변경 사항을 저장한다.
    • 한번 더 쿠키 값을 세팅하려고 redirect 함수에 메인 화면을 넘겨 준 결괏 값은 response로 받아와서 해당 response에 대해 이전에 설정한 2개의 쿠키값을 삭제하고, 로그인된 유저의 정보를 쿠키로 설정하며 response를 반환해 준다.
    • 만약 두 값이 일치하지 않는 경우, 다시 인증 코드 입력 화면으로 redirect 시켜 준다.
    • 코드 구현 후, 회원 가입을 재 진행한다. 이메일로 전송된 인증 코드를 입력 한다.
from django.shortcuts import render, redirect
from random import * 
from .models import *
from sendEmail.views import *

# Create your views here.
def index(request):
	# 생략

def signup(request):
	# 생략

def join(request):
	# 생략

def signin(request):
	# 생략

def verifyCode(request):
	# 생략

def verify(request):
    user_code = request.POST['verifyCode']
    cookie_code = request.COOKIES.get('code')
    if user_code == cookie_code:
        user = User.objects.get(id = request.COOKIES.get('user_id'))
        user.user_validate = 1
        user.save()
        
        response = redirect('main_index')
        response.delete_cookie('code')
        response.delete_cookie('user_id')
        response.set_cookie('user', user)
        return response
    else:
        return redirect('main_verifyCode')

def result(request):
	# 생략
  • 인증이 이루어진 과정은 아래와 같다.

Untitled