Static파일이란 웹 사이트 구성요소 중 Image, CSS, Script파일과 같이 그 내용이 고정되어 응답을 할 때 별도의 처리 없이 파일 내용을 그대로 보내주면 되는 파일을 의미합니다.
따라서 Static파일들은 웹 어플리케이션을 통하지 않고, 그 전단의 웹 서버에서 URI에 따른 파일 내용을 그대로 응답함으로써 직접 처리해 줄 수도 있습니다. 일례로, Nginx를 Reverse Proxy로 사용할 때 Static File들에 대한 요청을 Nginx가 직접 처리하도록 세팅하여 응답 속도를 향상시킬 수 있습니다. 또는 CDN과 같이 Static파일들만을 모아서 따로 관리하는 전담 서버를 통해 Static파일들을 처리하여 웹 서버의 Load를 줄이는 기법을 구현할 수도 있습니다.
Django에서는 Static파일들을 모듈별 Local영역과 Global영역 두 단계로 나누어서 관리를 합니다. Local영역에는 각 모듈에서 독자적으로 사용되는 Static파일들이 위치하고, Global영역(STATICFILES_DIRS)에는 사이트 전역에서 공통적으로 사용하는 Static파일들이 위치합니다.
또한, 개발 과정에서 각 모듈별로 분산되어 저장한 Static파일들을 한 데 모아서 통합된 Static디렉토리를 만들어주는 기능도 내장하고 있습니다(manage.py의 collectstatic명령). 이를 이용하면 완성한 프로젝트를 실제 운영 서버에 올릴 때 별도의 Static디렉토리를 생성해서 웹 서버에서 바로 응답하도록 하거나, 별도의 Static파일 전용 서버를 구축할 때 편리하게 사용할 수 있습니다.
이 글에서는 직전 글에서 작성한 예제에 CSS파일을 추가하는 방법에 대해 다루도록 하겠습니다.
Static파일 저장을 위한 디렉토리 생성하기
myapp모듈에서 사용할 Static파일들을 저장하는 디렉토리는 myapp/static/myapp입니다. 이렇게 디렉토리를 구성하는 이유는 Template파일과 마찬가지로 네임스페이스가 충돌하지 않도록 하기 위함입니다.
(venv)$ mkdir -p myapp/static/myapp
귀찮다고 해서 그냥 myapp/static디렉토리에 바로 myapp에서 사용할 Static파일들을 위치시키면, 다른 모듈에 같은 이름의 Static파일이 존재하는 경우 요청에 대해 잘못된 Static파일이 전달되는 충돌이 발생할 수 있습니다. 또한, 운영 서버에서 collectstatic명령으로 통합 static디렉토리를 생성할 때 어느 한쪽 파일이 다른 파일에 의해 덮어씌워져 누락되는 문제가 발생합니다.
이제 myapp/static/myapp/mypage.css파일을 다음과 같이 작성합니다. 간단한 예제로, 본문의 글자 색을 모두 파란색으로 바꿔 보도록 하겠습니다. (여기서는 예시를 위해 myapp디렉토리에 바로 CSS파일을 위치시켰지만, 실제 프로젝트에서는 css, js, image등과 같이 Static파일의 종류별 하위 디렉토리를 따로 구성하는 것이 좋습니다.)
@charset "utf-8"; body { color: blue; }
Template에 Static파일 삽입하기
myapp/templates/myapp/mypage.html파일을 다음과 같이 수정합니다. 강조 표시된 1,5번째 줄이 추가된 줄입니다.
{% load staticfiles %} <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="{% static 'myapp/mypage.css' %}" /> <title>Django Tutorial</title> </head> <body> {{ welcome_text }} </body> </html>
첫 번째 줄은 settings.py에 정의된 Static파일 관련 환경변수와 메소드들을 로드하기 위한 구문으로, 5번째 줄에서 static이라는 이름의 메소드를 호출하기 위해 삽입하였습니다.
5번째 줄에서는 Template랜더링 과정에서 static이라는 이름의 메소드를 호출하면서 매개변수로 'myapp/mypage.css'를 전달하며, 그 반환값은 Static파일을 찾을 수 있는 실제 경로가 됩니다.
'./manage.py runserver'를 실행하고 브라우저를 통해 /mypage로 접속해 보면 다음과 같이 CSS가 적용되서 본문 글자색이 파란색으로 바뀐 것을 볼 수 있습니다.
Global Static 디렉토리 추가하기
Django에서는 Static파일을 찾는 요청이 들어올 경우 우선 각 모듈 디렉토리 내에 위치하는 static디렉토리들을 순차적으로 검색하며 대상 파일을 찾습니다. 만약 여기서 찾지 못한 경우, 다음 단계로 Global Static 디렉토리를 찾기 시작하며, 여기서도 찾지 못한 경우 404 Not Found오류를 반환합니다.
Global Static 디렉토리는 특정 모듈에 종속되어 있지 않고 공통적으로 사용되는 Static파일들을 저장해야 할 경우 사용합니다. 예를 들어, 사이트 전체적으로 적용되는 테마나 사이트 로고 및 Favicon과 같은 파일들이 여기에 속합니다.
기본적으로 Django 프로젝트를 생성할 때 Global Static 디렉토리는 지정되어 있지 않으며, 필요할 경우 다음과 같이 settings.py의 STATICFILES_DIRS변수를 정의해 주면 됩니다.
STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static"), '/var/www/static/', ... )
위와 같이 설정하면 Static파일에 대한 요청이 들어왔을 때 Local영역에서 찾지 못한 경우 Global영역에서 'myproject/static'디렉토리를 찾아본 뒤, 그래도 없을 경우 마지막으로 '/var/www/static'디렉토리를 찾게 됩니다.
고급: Production과 Static파일의 관리
위에서 다룬 예시에서 Template파일의 첫 번째 줄을 지우고, 5번째 줄의 href 경로를 다음과 같이 직접 명시해도 정상적으로 CSS파일을 불러올 수 있습니다.
<link rel="stylesheet" href="/static/myapp/mypage.css" />
하지만 이렇게 하지 않고 staticfiles모듈에 포함된 static메소드를 사용해서 간접적으로 경로를 명시하는 이유는 추후 Production시 Static파일들을 가져올 경로를 외부 CDN으로 쉽게 변경하기 위함입니다.
즉, 개발 과정에서는 Static파일들을 프로젝트 내에 각 모듈별로 분산해 놓았다가, 개발 완료 후 Production 서버에서 실제 운영을 시작할 때는 이 파일들을 찾는 경로를 일괄적으로 CDN 서버 주소로 바꿔 주는 것이죠.
static 메소드를 사용하지 않고 위처럼 Static 파일 경로를 모두 하드코딩했다면, Production 서버에 올릴 때 Template에서 경로가 들어간 부분을 모두 찾아서 일일이 CDN서버 주소로 바꿔 줘야 할 것입니다.(노가다) 운영중에 CDN서버의 주소가 바뀌었거나 폭파되서 임시로 다시 되돌려야 한다면..ㅎㅎ 또다시 한 번 노가다를 해야하겠죠.
따라서 개발 과정에서부터 Static파일의 경로를 지정할 때 static 메소드를 사용하는 것이 향후 정신건강과 멘탈관리에 좋다고 할 수 있습니다.
Django와 CDN을 연동하는 자세한 방법은 다음 공식 매뉴얼을 참조해 주세요.
https://docs.djangoproject.com/en/1.8/howto/static-files/deployment/#staticfiles-from-cdn
- [Django Tutorial] 9. Production - uWSGI를 통해 Nginx 웹 서버와 연동하기 (11158) *1
- [Django Tutorial] 8. Production - setting.py설정, Static파일 모으기 (5315)
- [Django Tutorial] 7. 백엔드 콘솔에 Custom Command 추가하기 (3995)
- [Django Tutorial] 6. Database 연동하기 - Model설계, Migration (29899)
- [Django Tutorial] 4. URL Config, Template 및 View의 동작에 대한 이해 (8998)
- [Django Tutorial] 3. 프로젝트 및 App 생성, settings.py수정(DB연동, Migration), Runserver (12111)
- [Django Tutorial] 2. 개발 환경 세팅하기 - pyenv 및 virtualenv 활용 (6428)
- [Django Tutorial] 1. 파이썬 기반 웹 프레임워크 Django에 대한 소개 (10783) *2
- VirtualEnv를 통한 Python Sandbox 개발환경 구축하기 (4215)
- pyenv를 이용하여 여러 버전의 Python 동시에 사용하기 (14567) *3