파이썬으로 장고(Django) 공략하기: 입문 강의를 정리한 내용입니다.

views.py와 urls.py

  • views.py : 데이터를 처리하는 로직인 view 메소드를 정의하는 파일.
# first/views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello world")


def select(request):
    message = "수 하나를 입력해주세요."
    return HttpResponse(message)


def result(request):
    message = "추첨 결과입니다."
    return HttpResponse(message)
  • urls.py : view 메소드를 연결하고 요청 url을 정의하는 파일. 도메인 이하를 path라고 하며, 어떤 화면으로 연결할 지 선언하는 것을 라우팅이라고 한다.
  • path 함수의 첫 번째 인자는 클라이언트가 요청할 path를 말한다.
  • url을 설정하고 views.py에서 정의한 view 메소드와 연결한다.
# first/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name="index"),
    path('select/', views.select, name="select"),
    path('result/', views.result, name="result")
]
  • 프로젝트 폴더의 공통 urls.py에 웹 앱의 url를 추가할 때마다 계속 추가하는 것은 번거로우므로 웹 앱별로 다른 ruls.py를 선언하고 프로젝트 폴더의 공통 urls.py에 해당 파일들을 포함하도록 만든다.
  • 프로젝트 폴더에 웹 앱의 urls.py을 포함시킨다.
from django.contrib import admin
from django.urls import path, include

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

url 매핑 규칙

  • query paramter : url의 ? 뒤의 파라미터
  • path parameter : url 사이에 있는 파라미터. 파라미터 타입을 정의한다. 이 규칙의 예는 아래와 같다.
    • int : 정수형 숫자
    • str : 모든 문자열
    • slug : -(하이픈)이나 _(언더스코어)를 포함한 영숫자, 문자열
path('calendar/<int:year>/<int:month>', views.calendar, name="calendar")
  • urls.py에서 path parameter로 정의하면 view 메소드에서 해당 인자를 넘겨받을 수 있다.
def calendar(request, year, month):
    message = str(year) + "년 " + str(month) + "월 입니다."
    return HttpResponse(message)
  • 정규표현식을 사용해 url 패턴을 정의할 수 있다.
  • 파라미터는 P<name>pattern 형태로 나타낸다.
  • re_path 함수를 사용한다.
# first/urls.py
from django.urls import path, re_path
from . import views

re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive, name="year_archive")
# articles로 시작하는 path에 year라는 파라미터를 보내는 데 이는 0부터 9사이의 4자리 숫자로 끝난다.
# first/views.py
def year_archive(request, year):
    message = str(year) + "년 입니다!"
    return HttpResponse(message)

템플릿

  • template의 loder로 템플릿 파일을 로드하고, 해당 템플릿에 전달할 데이터를 설정하여 render에 인자로 넘길 수 있다.
# first/views.py
from django.template import loader
from datetime import datetime

def index(request):
    template = loader.get_template('index.html') # html 파일을 로딩
    now = datetime.now()
    context = {
        'current_date': now
    } # 템플릿에 전달할 데이터를 세팅할 수 있는 오브젝트
    return HttpResponse(template.render(context, request))
  • 템플릿에서 넘어온 변수는 {{ }} 사이에 나타낸다.
  • or 연산자로 나타내는 함수는 장고에 내장된 필터 함수이다. date 필터로 변수를 포매팅한다.
<!-- first/templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index html 페이지 입니다.</title>
</head>
<body>
    <p>변수를 표현해보자.</p>
    <p>{{ current_date }}</p>
    <p>장고에 내장된 date 필터로 변수를 포매팅하자.</p>
    <p>{{ current_date|date:"Y년 m월 d일 H시 i분 s초" }}</p>
</body>
</html>
  • 템플릿 파일 인식을위해 first 웹 앱을 INSTALLED_APPS 리스트에 추가해야 한다.
# firstdjango 프로젝트 폴더의 settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'first',
]

TIME_ZONE = 'Asia/Seoul' # 시간을 우리나라 시간으로 변경

템플릿에서 웹 앱의 urls.py에 정의된 name을 참조

<!-- first/templates/index.html -->
<a href="{% url 'select' %}">시작하기!</a>
# first/urls.py
path('select/', views.select, name="select")

shortcuts 모듈의 render 단축 메소드

  • 기존의 template 모듈의 loader로 템플릿를 불러오고 render로 인자를 넘기는 부분을 shortcuts 모듈의 render라는 단축 메소드로 코드를 줄일 수 있다.
# first/views.py
from django.shortcuts import render

def select(request):
    context = {"number": 4}
    return render(request, 'select.html', context)


def result(request):
    context = {'numbers': [1,2,3,4,5,6]}
    return render(request, 'result.html', context)
  • select.html에 나머지 연산자를 사용할 수 없으므로 divisibleby 필터로 홀짝을 비교하는 if 템플릿 언어를 추가한다.
<!-- select.html -->
<p>
    {% if number|divisibleby:2 %}
        짝수입니다.
    {% else %}
        홀수입니다.
    {% endif %}
</p>
<a href="{% url 'result' %}">결과보기</a>
  • result.html에 리스트의 요소를 차례로 출력하는 for문을 추가한다.
<!-- result.html -->
<ul>
    {% for num in numbers %}
    <li>{{ num }}</li>
    {% endfor %}
</ul>

스태틱 파일(정적 컨텐츠)

  • css, js, 이미지 파일 등을 말한다.
  • 스태틱 파일의 위치는 기본적으로 웹 앱 폴더 하위의 static 폴더에 둔다.
  • 프로젝트 폴더의 settings.py에서 스태틱 파일 위치, 즉 BASE_DIR를 static으로 추가한다.
  • 이는 각 웹 앱의 하위에 있는 static 폴더 안의 스태틱 파일을 읽어온다는 것을 뜻한다.
  • 단, 여러 웹 앱의 static 폴더 내에 같은 이름의 파일이 있는 경우 충돌이 발생할 수 있기 때문에 스태틱 파일 구조를 static/웹 앱 폴더명/으로 만들어야 한다.
# 프로젝트 폴더 settings.py
STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")
]
  • 마찬가지로 Template 파일도 충돌이 날 수 있으므로 templates/웨 앱 폴더명/ 하위에 html 파일을 만들어야 한다.
  • 폴더 구조가 바뀜에 따라 views.py의 템플릿명을 다음과 같이 수정한다.
# first/views.py
...
def select(request):
    context = {"number": 4}
    return render(request, 'first/select.html', context)
...
  • Template 파일에 추가한 이미지 파일을 불러온다.
  • 가장 상단에 load static을 추가해야 장고 스태틱 모듈을 불러올 수 있다.
{% load static %}
...
<img src="{% static 'first/thank-card.png' %}">

장고 템플릿의 블락(block)

  • 중복되는 코드만 따로 Template 파일로 만들어 코드를 재사용할 수 있다.
  • 베이스 템플릿의 blockendblock 사이에 중복되지 않는 코드가 들어가게 된다.
  • 여기서 block의 이름을 content라고 지정한다.
<!-- templates/first/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>로또 번호 추첨</title>
    <link rel="stylesheet" type="text/css" href="{% static 'first/styles.css' %}">
</head>
<body>
    {% block content %}
    {% endblock %}
</body>
</html>
  • body 태그 내부를 제외한 코드는 중복되므로 나머지 템플릿 파일을 수정한다.
  • 나머지 템플릿 파일의 첫 줄에 베이스 템플릿을 지정할 extends 구문을 선언하고 블록이 시작되는 위치를 block 구문으로 선언한다.
<!-- templates/first/index.html  -->
{% extends 'first/base.html' %}
{% load static %}
{% block content %}
    <p>변수를 표현해보자.</p>
    <p>{{ current_date }}</p>
    <p>장고에 내장된 date 필터로 변수를 포매팅하자.</p>
    <p>{{ current_date|date:"Y년 m월 d일 H시 i분 s초" }}</p>

    <br>

    <a href="{% url 'select' %}">시작하기!</a>

    <br>

    <img src="{% static 'first/thank-card.png' %}">
{% endblock %}
<!-- templates/first/result.html -->
{% extends 'first/base.html' %}
{% load static %}
{% block content %}
    <h3>추첨 번호는 다음과 같습니다</h3>
    <ul>
        {% for num in numbers %}
        <li>{{ num }}</li>
        {% endfor %}
    </ul>
{% endblock %}
  • result.html에 입력한 숫자와 랜덤한 숫자를 받을 수 있도록 select.html와 views.py를 수정한다.
<!-- templates/first/select.html -->
{% extends 'first/base.html' %}
{% block content %}
<p>수를 하나 입력해주세요.</p>

<form action="{% url 'result' %}" method="get">
    <input type="number" name="number">
    <button type="submit">결과보기</button>
</form>
{% endblock %}
  • get으로 넘긴 파라미터는 딕셔너리 형태로 담긴다.
  • 숫자를 랜덤하게 섞기 위한 random 모듈을 사용한다.
# first/views.py
import random

def result(request):
    # 요청 데이터가 딕셔너리 형태 담긴다
    # get이나 post로 넘어온 데이터는 문자열 형태가 된다.
    chosen = int(request.GET['number'])
    result = []
    if chosen >= 1 and chosen <= 45:
        result.append(chosen)

    box = [] # 입력하지 않은 숫자
    for i in range(0, 45):
        if chosen != i+1:
            box.append(i+1)

    random.shuffle(box)

    while len(result) < 6:
        result.append((box.pop()))

    context = {
        'numbers': result
    }
    return render(request, 'first/result.html', context)