웹 페이지를 구성할 때 쓰임이 정해져 있는 ‘움직이지 않는’ 파일을 의미한다.
js, css, 이미지 파일 등이 여기에 해당한다.
settings.py에서 static file을 디렉토리 별로 관리할 수 있다.
STATIC_URL = "static/"
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
STATICFILES_DIRS
: static 파일의 경로를 지정하는 변수이다. 프레임워크 문법이기 때문에 반드시 이름을 그대로 사용해야 한다.BASE_DIR
: 프로젝트의 루트 폴더 경로를 말한다. django 프로젝트 폴더 생성 시 자동으로 지정된다.STATIC_URL
: 웹 페이지 경로를 지정한다.위와 같이 설정했다면 프로젝트 루트폴더에 static 이름을 갖는 디렉토리를 생성하여 파일을 집어넣고, 브라우저에서 /static/filename.jpg
경로로 접근하면 해당 파일을 볼 수 있다.
# views.py
from django.http import FileResponse
def load_img(req, name):
img = open(f'static/ {name}', 'rb')
return FileResponse(img, content_type= 'image/jpeg' )
# urls.py
urlpatterns = [
path("image/<name>", views.load_img)
]
파이썬의 파일문법을 이용해서 직접 이미지를 불러오는 방법도 있다.
FileResponse
함수를 이용해 다양한 타입의 static file을 화면에 출력할 수 있다.
주로 특정 파일을 사용자에게 다운로드 받도록 하거나, 사용자가 첨부한 파일을 받아 처리하는 경우 이러한 방식으로 처리하는 것이 가능하다.
HTML과 같이 사용자에게 보여주는 틀을 말한다.
Template을 별도 관리하는 이유는 로직(python 코드)과 Look(HTML)을 분리하기 위해서이다.
django의 template 문법을 통해 HTML에 동적으로 변수를 할당하고, 파이썬과 유사하게 조건문 및 반복문의 사용 등이 가능하다.
settings.py
의 TEMPLATE 변수아래 템플릿 디렉토리를 선언하여 해당 디렉토리에 템플릿 파일들을 담는다.
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / 'templates'],
"APP_DIRS": True,
... (중략) ...
}
]
django가 제공하는 render 함수를 통해 해당 템플릿 파일을 가져올 수 있다.
# urls.py
urlpatterns = [
path("hello/", views.index),
]
# views.py
from django.shortcuts import render
def index(req):
return render(req, 'hello.html')
이렇게 하면 ROOT/templates/hello.html
경로에 있는 html 파일을 불러온다.
render 함수는 HTML 외의 다양한 형식의 파일을 렌더링할 수 있는데 자세한 것은 따로 공부해두면 좋다.
참고 : https://docs.djangoproject.com/en/4.2/ref/templates/builtins/
프레임워크에 문법에 따라 Template을 동적으로 렌더링할 수 있다.
HTML에 변수를 선언하면 렌더링시 해당 부분을 파이썬 코드의 데이터로 교체할 수 있다.
Template에서 교체할 컨텐츠를 중괄호 2개 {{ }}
로 표시한다.
함수에서는 Template에서 교체할 컨텐츠를 딕셔너리에 담아 render 함수의 인자로 사용한다.
이때 템플릿에 선언한 변수명과 함수에서 전달하는 딕셔너리의 key가 동일해야 한다.
<!-- HTML -->
<h2>{{title}}</h2>
<p>{{content}}</p>
# views.py
def chapter(req, id):
chapters = {
"01": {"title": "Setting & Deploy" , "content": "Setting & Deploy is ..." },
"02": {"title": "Routing & View" , "content": "Routing & View is ..." },
}
return render(req, 'index.html', chapters[id])
# urls.py
urlpatterns = [
path("chapter/<id>/", views.chapter),
]
변수에는 filter를 선언하여 해당 변수에 대한 동적인 처리를 할 수 있다.
외우기보다는 필요한 것을 그때그때 공식문서에 찾아 사용하면서 자연스럽게 익히자
{{key | filter}}
형식으로 사용할 수 있다.def index(req):
d = {
'title': 'django',
'content': '<a href="https://www.djangoproject.com/">Django</a> is...'
}
return render(req, 'index.html', d)
<!-- HTML -->
<p>{{content}}</p>
위와 같이 렌더링 시 HTML 태그를 직접 담아 전송할 경우 이를 태그로 처리하지 않고 그대로 문자열이 된다.
safe 필터를 이용하면 문자열을 태그로 처리하여 사용할 수 있도록 해준다.
<!-- HTML -->
<p>{{content | safe}}</p>
Template 내에서 조건문 및 반복문을 사용할 수 있는 문법이다.
<!-- HTML -->
{% if variable %}
<p>조건이 참입니다.</p>
{% elif another_variable %}
<p>다른 조건이 참입니다.</p>
{% else %}
<p>모든 조건이 거짓입니다.</p>
{% endif %}
<!-- HTML -->
{% for item in items %}
<p>{{ item }}</p>
{% empty %}
<p>아이템이 없습니다.</p>
{% endfor %}
위와같이 선언하면 되며, 파이썬의 문법을 그대로 사용할 수 있다.
예를들어 딕셔너리 형태의 파일의 key, value를 모두 사용하고 싶다면 .items
와 같은 형태로 사용할 수 있다. (파이썬 문법과 달리 소괄호를 빼야함에 유의하자)
<ul>
{% for key, item in item_dict.items %}
<li>{{key}} : {{ item }}</li>
{% empty %}
<li>아이템이 없습니다.</li>
{% endfor %}
</ul>
def control(req):
data = {
'item_list' : ['사과', '딸기', '메론'],
'item_dict' : {
'강아지' : 4,
'고양이' : 4,
'비둘기' : 2
}
}
return render(req, 'control.html', data)
템플릿 상속을 위해 사용한다
웹페이지에서 공통적으로 사용이 되는 레이아웃, 헤더, footer 등에 사용한다.
상속받은 extends 템플릿에서 block을 사용하여 특정 부분만 변경할 수 있다.
프로젝트의 기능별로 별도의 어플리케이션을 정의하여 구현하는 것
이를 통해 얻게되는 장점은 크게 두 가지가 있다.
python manage.py startapp <애플리케이션 이름>
settings.py에 INSTALLED_APPS에 애플리케이션 이름을 추가해야한다.
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"<application_name>",
]
기본적으로 관리자 기능이 등록되어있다.
기본적으로 모든 url은 프로젝트 디렉토리의 urls.py
에서 관리된다.
하지만 프로젝트 디렉토리와 어플리케이션 디렉토리의 경로가 다르기 때문에 그대로 넣어 사용하면 오류가 발생할 가능성이 높다.
때문에 어플리케이션 별로 urls.py를 별도로 생성하고 django가 제공하는 include
함수를 이용해 묶어준다.
# project/urls.py
from django.urls import path, include
urlpatterns = [
path("blog/", include('blog.urls')),
]
# application/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("list/", views.post_list)
]
# application/views.py
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
def post_list(req: HttpRequest) -> HttpResponse:
posts = [
{ 'id': 1, 'title': 'html', 'content' : 'html is ...' },
{ 'id': 2, 'title': 'css', 'content' : 'css is ...' },
{ 'id': 3, 'title': 'javascript' , 'content' : 'javascript is ...' },
]
return HttpResponse(posts)
blog/
로 시작하는 모든 경로는 어플리케이션의 urls.py
에서 처리한다.blog/list/
주소가 오면 어플리케이션의 post_list
함수가 실행된다.애플리케이션의 템플릿 역시 프로젝트 폴더의 templates 폴더에서 처리된다.
모든 어플리케이션의 Template를 하나의 디렉토리에서 처리해도 되지만, 구분을 위해서는 별도의 하위 폴더를 만들어서 관리하는 것이 권장된다.
번외 : Type Hinting
파이썬 및 Javascript는 인자 등을 주고 받을 때 타입체크를 하지 않는다.
→ int로만 작동하는 함수이지만 리스트, 문자열, 딕셔너리 등등 죄다 받을 수 있다.
소규모 프로젝트에서는 상관없지만 인터페이스가 복잡해지는 대규모 프로젝트에서 이로인한 에러 등 문제가 발생할 수 있다.이때문에 파이썬은 3.9버전부터 Type Hinting 기능을 제공하고, Javascript는 TypeScript 언어가 생겨났다.
장고는 기본적으로 어드민페이지를 제공한다.
우리가 할 것은 어드민 계정을 추가하는 것 뿐이다.
그전에 어드민 계정을 추가한다는 것은 계정 데이터를 추가한다는 것이므로, 이를 저장할 DB가 필요하다.
python [manage.py](http://manage.py/) makemigrations
python manage.py migrate
VS Code에 익스텐션을 설치하면 데이터베이스를 확인할 수 있다.
이번 과정에서는 SQLite Viewer
를 사용하였다.
migrate를 실행하지 않았을 때
migrate 수행 후
python manage.py createsuperuser