프로젝트와 앱은 역할이 다르다
Django를 처음 시작하면 가장 먼저 헷갈리는 말이 프로젝트와 앱이다. 둘 다 폴더로 보이기 때문에 비슷해 보이지만, 맡은 일이 다르다.
프로젝트는 하나의 웹사이트 전체를 조립하는 단위다. 설정, 전체 URL 연결, 배포 진입점처럼 사이트 전체에 영향을 주는 파일을 가진다. 예를 들어 블로그 서비스를 만든다면 데이터베이스 설정, 언어와 시간대 설정, 어떤 앱을 사용할지 정하는 일은 프로젝트가 담당한다.
앱은 기능 단위다. 게시판, 계정, 상품, 주문, 댓글처럼 독립적으로 설명할 수 있는 기능을 하나의 앱으로 나눈다. Django 공식 문서도 프로젝트를 "특정 Django 웹사이트를 위한 설정의 모음"으로, 앱을 "블로그나 투표처럼 어떤 일을 하는 웹 애플리케이션"으로 설명한다.1
간단히 말하면 다음과 같다.
프로젝트: 전체 설정과 조립
앱: 실제 기능 구현
하나의 프로젝트 안에는 여러 앱이 들어갈 수 있다. 반대로 잘 만든 앱은 다른 프로젝트에서 다시 사용할 수도 있다. 예를 들어 accounts 앱을 사용자 가입과 로그인 기능으로 잘 분리해 두면, 다른 서비스에서도 비슷한 구조로 가져다 쓸 수 있다.
AI 생성 이미지
startapp으로 앱 만들기
Django 프로젝트를 만든 뒤 기능을 추가할 때는 보통 startapp 명령을 사용한다.
python manage.py startapp boards이 명령은 boards라는 앱 폴더를 만든다. 게시판 기능을 만든다고 가정하면 자연스러운 이름이다. 생성된 구조는 보통 다음과 같다.
boards/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py각 파일은 처음에는 비어 있거나 짧은 코드만 들어 있다. 하지만 Django가 기대하는 기본 위치이므로 역할을 알고 있어야 한다.
models.py
models.py는 데이터 구조를 정의하는 파일이다. 게시판 앱이라면 Post, Comment 같은 모델을 여기에 만든다. Django의 모델은 데이터베이스 테이블과 연결된다. 나중에 ORM을 배울 때 자세히 다루겠지만, 지금은 "이 앱이 저장할 데이터의 모양을 적는 곳"이라고 이해하면 된다.
views.py
views.py는 요청을 처리하는 코드를 두는 곳이다. 사용자가 /boards/ 주소로 들어왔을 때 게시글 목록을 보여 줄지, 글 작성 화면을 보여 줄지 결정하는 함수나 클래스를 작성한다.
이름 때문에 헷갈릴 수 있지만 Django에서 View는 화면 파일이 아니다. View는 요청을 받아 응답을 만드는 Python 코드다. 화면 HTML은 보통 Template이 담당한다.
admin.py
admin.py는 Django 관리자 페이지에 모델을 등록하는 곳이다. 예를 들어 Post 모델을 관리자 화면에서 추가·수정·삭제하고 싶다면 이 파일에 등록 코드를 작성한다.
관리자 페이지는 개발 중 데이터를 확인하거나 내부 운영 도구를 만들 때 유용하다. 앱마다 관리할 데이터가 다르기 때문에 관리자 등록도 앱 안에 둔다.
apps.py
apps.py에는 앱 설정 클래스가 들어 있다. 보통 BoardsConfig 같은 AppConfig 클래스가 생성된다.
from django.apps import AppConfig
class BoardsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "boards"처음에는 이 파일을 자주 수정하지 않는다. 하지만 이 앱의 이름, 기본 설정, 시작 시 필요한 설정을 Django에 알려 주는 역할을 한다. Django는 설치된 앱 목록을 읽고 각 앱의 설정 정보를 등록한다.2
tests.py
tests.py는 테스트 코드를 작성하는 곳이다. 처음에는 비어 있지만, 기능이 늘어나면 "게시글이 제대로 생성되는가", "권한이 없는 사용자가 수정할 수 없는가" 같은 확인 코드를 여기에 작성할 수 있다.
프로젝트가 커지면 tests.py 하나가 길어질 수 있다. 그때는 tests/ 폴더로 나누어도 된다. 처음부터 복잡하게 나눌 필요는 없다.
migrations 폴더
migrations 폴더는 모델 변경 이력을 저장한다. models.py에 Post 모델을 추가하고 마이그레이션을 만들면, Django는 그 변경 내용을 이 폴더 안에 파일로 기록한다.
마이그레이션은 데이터베이스 구조를 안전하게 바꾸기 위한 기록이다. 단순한 임시 파일이 아니므로 함부로 삭제하거나 수정하지 않는 편이 좋다. 특히 이미 다른 사람과 함께 개발 중이거나 운영 데이터베이스에 적용된 마이그레이션이라면 더 조심해야 한다.
앱을 만들었다고 바로 연결되는 것은 아니다
startapp은 폴더를 만들어 줄 뿐이다. Django가 그 앱을 프로젝트의 일부로 인식하려면 settings.py의 INSTALLED_APPS에 등록해야 한다.
예를 들어 프로젝트 설정 파일에 다음처럼 추가한다.
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"boards",
]또는 앱 설정 클래스를 명시해도 된다.
INSTALLED_APPS = [
# ...
"boards.apps.BoardsConfig",
]둘 다 자주 쓰인다. 앱에 별도 설정 클래스가 있다면 boards.apps.BoardsConfig처럼 명시하는 방식이 더 분명하다.
왜 이 등록이 필요할까? Django는 프로젝트 폴더 안의 모든 디렉터리를 자동으로 앱이라고 판단하지 않는다. INSTALLED_APPS에 적힌 앱을 기준으로 앱 등록소를 만들고, 그 앱들의 모델과 설정을 읽는다. 이 과정이 있어야 models.py의 모델을 찾고, 마이그레이션을 만들고, 관리자 등록이나 앱 내부 템플릿 탐색도 정상적으로 사용할 수 있다.2
앱을 만들었는데 makemigrations가 "변경 사항이 없다"고 말한다면, 먼저 INSTALLED_APPS에 등록했는지 확인해야 한다. 물론 모델 파일을 저장했는지, 모델 클래스가 models.Model을 상속하고 있는지도 함께 확인해야 한다.
다만 중요한 점이 하나 있다. INSTALLED_APPS에 등록했다고 해서 URL이 자동으로 연결되지는 않는다. 앱을 활성화하는 것과 사용자의 주소를 연결하는 것은 별개의 일이다. URL 연결은 urls.py에서 따로 해야 한다.
URL은 프로젝트에서 모으고 앱에서 나눈다
프로젝트에는 보통 전체 URL을 담당하는 urls.py가 있다. 예를 들어 프로젝트 패키지 이름이 config라면 다음 파일이다.
config/urls.py처음에는 모든 URL을 이 파일에 직접 적고 싶을 수 있다. 하지만 기능이 늘어나면 금방 복잡해진다. 게시판 URL, 계정 URL, 상품 URL이 한 파일에 섞이면 어느 기능의 주소인지 찾기 어려워진다.
그래서 보통 앱마다 urls.py를 따로 만든다. startapp 명령이 앱의 urls.py를 자동으로 만들어 주지는 않으므로 직접 생성한다.
boards/
urls.py
views.py게시판 앱의 URL은 boards/urls.py에 둔다.
# boards/urls.py
from django.urls import path
from . import views
app_name = "boards"
urlpatterns = [
path("", views.post_list, name="post_list"),
]그리고 프로젝트의 config/urls.py에서 이 앱의 URL을 포함한다.
# config/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("boards/", include("boards.urls")),
]이제 사용자가 /boards/로 요청하면 프로젝트 URL 설정이 먼저 boards/까지 보고, 나머지 처리를 boards.urls에 넘긴다. 앱은 자기 기능 안의 세부 주소만 관리하면 된다. 위 예시에서는 boards/urls.py의 빈 문자열 경로 ""가 최종적으로 /boards/ 주소와 연결된다.
이 구조의 장점은 분명하다. 게시판 주소를 바꾸고 싶으면 boards/urls.py를 보면 된다. 계정 주소를 바꾸고 싶으면 accounts/urls.py를 보면 된다. 프로젝트의 urls.py는 전체 목차처럼 각 앱을 연결하는 역할에 집중한다.
템플릿 위치도 기준을 정해 둔다
화면 파일인 템플릿도 기능이 늘어나면 위치가 중요해진다. 기본 원칙은 간단하다.
여러 앱이 함께 쓰는 템플릿은 프로젝트 공통
templates/에 둔다.특정 앱에서만 쓰는 템플릿은 그 앱 안에 둔다.
예를 들어 전체 레이아웃은 다음처럼 둘 수 있다.
templates/
base.html게시판 목록 화면은 앱 내부에 둔다.
boards/
templates/
boards/
post_list.html중간에 boards/templates/post_list.html이 아니라 boards/templates/boards/post_list.html처럼 앱 이름 폴더를 한 번 더 넣는 이유가 있다. 다른 앱에도 post_list.html 같은 이름이 생길 수 있기 때문이다. 템플릿 이름이 겹치면 Django가 엉뚱한 파일을 먼저 찾을 수 있다.
그래서 View에서는 다음처럼 앱 이름까지 포함해 렌더링한다.
return render(request, "boards/post_list.html", context)프로젝트 공통 템플릿 폴더를 쓰려면 settings.py의 TEMPLATES 설정도 확인해야 한다.
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
# ...
],
},
}
]DIRS는 프로젝트 공통 템플릿 위치를 알려 준다. APP_DIRS가 True이면 Django는 설치된 앱 내부의 templates/ 폴더도 찾는다. 이때 앱 내부 템플릿을 찾으려면 해당 앱이 INSTALLED_APPS에 등록되어 있어야 한다.
앱은 기술이 아니라 기능으로 나눈다
앱을 나눌 때 흔한 실수는 기술 계층으로 나누는 것이다.
views_app/
models_app/
templates_app/이런 식으로 나누면 Django의 기본 구조와 어긋난다. Django 앱은 "View를 모아 둔 곳"이나 "Model을 모아 둔 곳"이 아니다. 앱은 하나의 기능 영역이다.
좋은 예는 다음과 같다.
accounts/ # 회원가입, 로그인, 프로필
boards/ # 게시글, 댓글
products/ # 상품 목록, 상품 상세
orders/ # 주문, 결제 흐름각 앱 안에는 그 기능에 필요한 models.py, views.py, urls.py, admin.py, tests.py가 들어간다. 이렇게 두면 특정 기능을 수정할 때 어느 폴더를 봐야 하는지 명확하다.
물론 처음부터 너무 잘게 나눌 필요는 없다. 게시글과 댓글이 강하게 묶여 있다면 처음에는 boards 앱 하나에 둘 수 있다. 나중에 댓글 기능이 매우 커지고 독립적인 정책이 많아지면 comments 앱으로 분리할 수 있다.
앱을 나눌지 고민될 때는 다음 질문을 해 보면 좋다.
이 기능은 독립적인 이름으로 설명할 수 있는가?
이 기능만의 URL, 모델, 화면이 있는가?
다른 기능과 섞였을 때 파일이 지나치게 커지는가?
나중에 다른 프로젝트에서도 재사용할 가능성이 있는가?
모든 질문에 "예"라고 답해야만 앱을 나누는 것은 아니다. 하지만 이런 질문은 경계를 정하는 데 도움이 된다. 처음에는 조금 크게 시작하고, 파일이 너무 커지거나 책임이 분명히 갈라질 때 앱을 나누어도 늦지 않다.
기본 구조 예시
게시판과 계정 기능이 있는 작은 프로젝트라면 다음 정도의 구조로 시작할 수 있다.
myproject/
manage.py
config/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
accounts/
__init__.py
admin.py
apps.py
models.py
urls.py
views.py
tests.py
migrations/
__init__.py
boards/
__init__.py
admin.py
apps.py
models.py
urls.py
views.py
tests.py
migrations/
__init__.py
templates/
boards/
post_list.html
templates/
base.html여기서 config는 전체 설정을 담당한다. accounts와 boards는 각각 기능을 담당한다. 공통 레이아웃은 프로젝트 루트의 templates/base.html에 둔다. 게시판에서만 쓰는 템플릿은 boards/templates/boards/ 아래에 둔다.
이 구조를 지키면 기능이 늘어나도 파일을 찾는 기준이 흔들리지 않는다. 새 기능이 생기면 먼저 "이 기능은 어느 앱에 속하는가?"를 묻고, 그다음에 모델, View, URL, 템플릿을 적절한 위치에 둔다.
구조를 이해하면 다음 단계가 쉬워진다
Django 프로젝트는 처음에는 파일이 많아 보인다. 하지만 기준은 단순하다.
프로젝트는 전체 설정과 연결을 맡는다. 앱은 기능 단위를 맡는다. 앱을 만들면 INSTALLED_APPS에 등록해야 Django가 그 앱을 인식한다. URL은 프로젝트에서 모으고, 세부 URL은 앱에서 관리한다. 템플릿은 공통 파일과 앱 전용 파일을 구분해 둔다.
이 기준만 잡아도 프로젝트가 커질 때 덜 흔들린다. 다음 장에서는 이 구조 위에서 실제 요청이 URL과 View를 거쳐 어떻게 응답으로 바뀌는지 살펴본다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.