본문으로 건너뛰기
김신건의 로그

[Django] 개요와 프로젝트 구조

· 수정 · 📖 약 2분 · 746자/단어 #django #python #web-framework #mtv
django overview, django project structure, django app, MTV pattern, django architecture

정의

Django는 2003년 시작된 Python 풀스택 웹 프레임워크. “Web framework for perfectionists with deadlines”라는 모토대로 batteries-included(ORM, 관리자, 인증, 폼, 마이그레이션, 캐싱 등 기본 내장). MTV(Model-Template-View) 아키텍처. Instagram, Pinterest, Mozilla 등 대규모 운영 사례.

MTV 패턴

전통적인 MVC와 약간 다른 명명.

Django전통 MVC역할
ModelModelDB 스키마와 비즈니스 로직
TemplateViewHTML 렌더링
ViewControllerHTTP 요청 처리
URL DispatcherRouterURL → View 매핑

요청 흐름: URL → View → (Model 조회/변경) → Template 렌더링 → Response

요청 처리 흐름

flowchart LR
    Client["클라이언트"] -->|"HTTP 요청"| MW1["Request Middleware"]
    MW1 --> URLConf["URL Dispatcher"]
    URLConf --> View["View"]
    View --> Model["Model / ORM"]
    Model --> View
    View --> Template["Template Engine"]
    Template --> MW2["Response Middleware"]
    MW2 -->|"HTTP 응답"| Client

미들웨어는 요청/응답 양방향을 모두 가로챌 수 있다. 인증, 세션, CSRF, 캐싱 등이 여기 위치한다.

프로젝트 구조

django-admin startproject myproject
cd myproject
python manage.py startapp blog
myproject/
├── manage.py              # CLI 진입점
├── myproject/             # 프로젝트 설정 패키지
│   ├── __init__.py
│   ├── settings.py        # 설정
│   ├── urls.py            # 루트 URL conf
│   ├── asgi.py            # ASGI 진입점
│   └── wsgi.py            # WSGI 진입점
├── blog/                  # 앱
│   ├── __init__.py
│   ├── admin.py           # 관리자 등록
│   ├── apps.py            # 앱 설정
│   ├── models.py          # 데이터 모델
│   ├── views.py           # 뷰
│   ├── urls.py            # 앱별 URL (관례)
│   ├── tests.py
│   └── migrations/        # DB 마이그레이션
└── templates/             # 템플릿 (관례)

프로젝트 = 사이트, 앱 = 기능 단위. 한 프로젝트에 여러 앱. 앱은 독립적이고 재사용 가능하도록 작성.

첫 모델

# blog/models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

마이그레이션 생성과 적용:

python manage.py makemigrations
python manage.py migrate

첫 뷰와 URL

# blog/views.py
from django.shortcuts import render
from .models import Post

def post_list(request):
    posts = Post.objects.all()
    return render(request, "blog/post_list.html", {"posts": posts})

# blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("", views.post_list, name="post-list"),
]

# myproject/urls.py
from django.urls import include, path

urlpatterns = [
    path("blog/", include("blog.urls")),
]

템플릿

{# templates/blog/post_list.html #}
{% for post in posts %}
    <h2>{{ post.title }}</h2>
    <p>{{ post.body|truncatewords:30 }}</p>
{% empty %}
    <p>No posts.</p>
{% endfor %}

개발 서버

python manage.py runserver        # localhost:8000
python manage.py runserver 8080
python manage.py runserver 0.0.0.0:8000    # 외부 접속

프로덕션엔 절대 사용 X. Gunicorn/Uvicorn + nginx.

settings.py 핵심

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "blog",          # 우리 앱
]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "mydb",
        "USER": "myuser",
        "PASSWORD": "...",
        "HOST": "localhost",
        "PORT": "5432",
    }
}

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

DEBUG = True       # 프로덕션에선 반드시 False
SECRET_KEY = "..."  # 절대 커밋 X
ALLOWED_HOSTS = ["example.com"]

manage.py 자주 쓰는 명령

python manage.py startapp blog          # 앱 생성
python manage.py makemigrations         # 마이그레이션 파일 생성
python manage.py migrate                # DB에 적용
python manage.py createsuperuser        # 관리자 계정
python manage.py shell                  # IPython/REPL
python manage.py dbshell                # DB CLI
python manage.py collectstatic          # 정적 파일 수집
python manage.py test                   # 테스트
python manage.py runserver

Django vs Flask vs FastAPI

DjangoFlaskFastAPI
스타일배터리 포함마이크로API 우선
ORM내장SQLAlchemy 등외부
관리자내장XX
비동기부분 (3.1+)부분네이티브
학습 곡선
적합일반 웹앱, CMS작은 API/앱API, 마이크로서비스

버전과 LTS

버전출시지원 종료비고
4.2 LTS2023-042026-04이전 LTS
5.02023-122025-04
5.12024-082025-12
5.2 LTS2025-042028-04현재 LTS

LTS는 3년 지원. 프로덕션은 LTS 권장.

함정

1. DEBUG = True 를 프로덕션에 두면 안 된다

에러 발생 시 스택 트레이스, 로컬 변수, settings 값까지 브라우저에 노출된다. SECRET_KEY 도 유출 위험이 있다. 프로덕션에서는 반드시 DEBUG = FalseALLOWED_HOSTS 설정.

2. N+1 쿼리

# ✗ 루프마다 쿼리 발생 (FK 마다 SELECT)
for post in Post.objects.all():
    print(post.author.name)

# ✓ select_related 로 JOIN 한 번에
for post in Post.objects.select_related("author"):
    print(post.author.name)

ORM 이 편리하지만 쿼리 수를 놓치기 쉽다. django-debug-toolbarORM 고급 를 통해 쿼리 수를 확인해야 한다.

3. 마이그레이션 충돌

팀 개발 시 두 브랜치가 동시에 makemigrations 를 실행하면 번호가 충돌한다. squashmigrations 또는 충돌 파일 수동 정리로 해소. 자세히는 Django Migrations 참조.

4. SECRET_KEY 노출

.env 또는 환경 변수로 관리해야 한다. 실수로 git commit 에 포함되면 레포가 public 이 되는 순간 키 탈취 가능. django-environ / python-decouple 로 환경 변수 분리를 권장.

5. ALLOWED_HOSTS 미설정

DEBUG = False 일 때 ALLOWED_HOSTS = [] 면 모든 요청이 400 응답. 도메인/IP 를 정확히 나열해야 한다.

관련 위키

이 글의 용어 (12개)
[Django] 마이그레이션: makemigrations, migrate, 데이터 마이그레이션django
정의 Django 마이그레이션은 모델 변경을 DB 스키마 변경으로 변환·기록하는 시스템. 는 모델과 현재 마이그레이션 상태를 비교해 새 마이그레이션 파일 생성. 는 DB에 적용.…
[Django] 배포: Gunicorn, Uvicorn, whitenoise, Dockerdjango
정의 Django 프로덕션 배포는 WSGI/ASGI 서버 + 리버스 프록시 + 정적 파일 + DB + 캐시 + 큐 조합. runserver는 개발 전용. nginx + gunic…
[Django] 인증: User, login, permissionsdjango
정의 Django는 User 모델, 인증·세션, 권한·그룹을 기본 제공한다. 앱이 핵심. 비밀번호 해싱(PBKDF2, scrypt, Argon2), 세션, 권한, 그룹, 비밀번호…
[Django] 테스트: TestCase, Client, factory_boydjango
정의 Django는 표준 라이브러리 기반 TestCase를 제공한다. 트랜잭션 격리, fixtures, test client, DB 셋업 자동화. 실무는 + 가 사실상 표준. 기…
[Django] Admin: 자동 생성 관리자 페이지django
정의 Django Admin은 모델 등록만으로 CRUD UI 자동 생성하는 내장 백오피스. 내부 운영 도구, 콘텐츠 관리(CMS) 등에 강력. 권한 시스템 통합. Rails에는 …
[Django] DRF 개요: Serializer, ViewSet, Routerdjango
학습 로드맵 이 페이지는 개요. 처음 접하는 사람은 아래 순서로 읽으면 자연스럽다: DRF 는 파이프라인이 핵심. 한번 그림으로 보면 이해가 쉽다: 정의 Django REST F…
[Django] Model과 Field 타입django
정의 Django 모델은 DB 테이블의 Python 표현이다. 상속, 클래스 속성 = 컬럼, 메타 클래스 = 테이블 설정. 모델 정의 후 + 로 DB 스키마 자동 생성. 기본 정…
[Django] ORM 심화: N+1, prefetch, Subquery, Windowdjango
정의 Django ORM은 SQL을 잘 모르는 개발자에게도 안전하지만 비효율을 숨기기 쉽다. N+1, 비효율 JOIN, 큰 결과셋 메모리 폭발이 흔한 함정. selectrelat…
[Django] settings 관리: 환경 분리, secrets, 12-factordjango
정의 Django settings는 단일 Python 파일에 모든 설정을 두는 게 기본이지만, 환경별 분리·비밀 정보 분리·12-factor 원칙 적용이 실무 표준. 개발/스테이…
[Django] Template 언어: 태그, 필터, 상속django
정의 Django Template Language (DTL)는 HTML과 Python 사이의 안전한 표현 언어. 임의 Python 실행 차단(보안), 로 변수, 로 태그, 로 필…
[Django] URL 디스패치: path, re_path, includedjango
정의 Django는 URL 패턴 리스트로 요청을 view에 라우팅한다. 1.01.x는 (regex만), 2.0+ (간결한 converter 문법)와 (regex) 두 방식. 기본…
[Django] View: 함수 기반 vs 클래스 기반django
정의 Django View는 HTTP 요청을 받아 응답을 반환하는 callable. 두 스타일이 공존. - FBV (Function-Based View): 일반 함수. 간단하고 …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기