본문으로 건너뛰기 Django 기초 | Python 풀스택 웹 프레임워크 시작하기

Django 기초 | Python 풀스택 웹 프레임워크 시작하기

Django 기초 | Python 풀스택 웹 프레임워크 시작하기

이 글의 핵심

Django 기초: Python 풀스택 웹 프레임워크 시작하기. Django 시작하기·모델 (Model).

들어가며

Django는 “배터리 포함(Batteries Included)” 철학의 Python 웹 프레임워크입니다. 인증, ORM, Admin, 폼 검증, 보안(CSRF, XSS, SQL Injection 방어) 등 웹 애플리케이션에 필요한 거의 모든 기능이 기본 제공됩니다.

이 글에서 다루는 내용

  • Django의 역사와 설계 철학: 왜 “신문사를 위한 프레임워크”인가?
  • MVT 아키텍처: Model-View-Template 패턴의 동작 원리
  • ORM의 내부 구조: 쿼리셋의 지연 평가와 N+1 문제
  • 마이그레이션 시스템: 데이터베이스 스키마 변경의 자동화
  • Admin 사이트: 왜 Django Admin은 특별한가?
  • 실무 패턴: 쿼리 최적화, 캐싱, 보안, 배포

0. Django의 역사와 설계 철학

신문사에서 탄생한 프레임워크

Django는 2003년 미국 캔자스주 로렌스의 Lawrence Journal-World 신문사에서 탄생했습니다. 웹 개발자 Adrian HolovatySimon Willison이 신문 기사, 사진, 비디오를 빠르게 웹에 게시하는 시스템을 만들하다가 공통 패턴을 프레임워크로 분리한 것이 Django의 시작입니다.

2005년 오픈소스로 공개된 Django는 다음 철학을 표방했습니다:

  1. Don’t Repeat Yourself (DRY): 중복을 제거하고 재사용 가능하게
  2. Loose coupling, tight cohesion: 각 컴포넌트는 독립적이되, 함께 잘 동작
  3. Explicit is better than implicit: 마법 같은 동작보다 명시적 선언
  4. Batteries included: 인증, Admin, ORM 등 풀스택 기능 제공

왜 “신문사” 배경이 중요할까? 신문사는 빠른 마감, 대량의 콘텐츠, 복잡한 워크플로를 다루는 곳입니다. Django는 처음부터 “빠르게 기능을 만들으며, 안전하게 운영하며, 쉽게 확장할 수 있어야 한다”는 현실적 요구에 최적화되었습니다.

MTV vs MVC: Django만의 용어

웹 프레임워크는 보통 MVC(Model-View-Controller) 패턴을 따릅니다. Django도 유사하지만, 용어가 다릅니다:

전통적 MVCDjango MVT역할
ModelModel데이터베이스 스키마, 비즈니스 로직
ViewTemplate사용자에게 보여지는 HTML
ControllerViewHTTP 요청을 처리하는 함수/클래스

왜 헷갈리게 만들었을까? Django 개발자들은 “Controller”라는 용어가 프레임워크 내부(URL 라우팅)에 더 가깝으며, View는 “사용자가 보는 것”이 아니라 “로직”이라고 생각했습니다. Template이 정말 “사용자가 보는 View”에 가깝다는 주장입니다.

ORM의 철학: “SQL을 숨기되, 우회로는 열어두기”

Django ORM은 데이터베이스 독립성을 제공합니다. PostgreSQL, MySQL, SQLite, Oracle 등을 같은 Python 코드로 다룰 수 있습니다:

# Python ORM 코드
Post.objects.filter(published=True).order_by('-created_at')[:10]

# PostgreSQL SQL
SELECT * FROM blog_post WHERE published = TRUE ORDER BY created_at DESC LIMIT 10;

# MySQL SQL (동일)
SELECT * FROM blog_post WHERE published = 1 ORDER BY created_at DESC LIMIT 10;

하지만 성능이 중요한 경우, raw SQL을 직접 쓸 수 있는 “탈출구”도 제공합니다:

Post.objects.raw('SELECT * FROM blog_post WHERE ...')

이는 “추상화는 좋지만, 현실에서는 최적화가 필요할 때가 있다”는 실용주의를 반영합니다.

”Admin은 사이트 관리자용, 사용자용 UI가 아니다”

Django Admin은 내부 관리자를 위한 CRUD 인터페이스입니다. 많은 초보자가 “Admin을 커스터마이징해서 일반 사용자에게 제공”하려 하지만, Django 공식 문서는 이를 권장하지 않습니다:

Admin은 사이트 관리자가 데이터를 빠르게 수정하기 위한 도구입니다. 일반 사용자용 UI는 별도로 만들어야 합니다.

왜? Admin은 권한 체크가 느슨하며, 모든 모델을 노출하며, 성능 최적화가 안 되어 있습니다. “신문사 편집자가 급하게 기사를 수정하는” 용도로는 완벽하지만, 일반 사용자용으로는 부적합합니다.

마이그레이션의 역사: South → Django 1.7

초기 Django(~1.6)에는 마이그레이션 시스템이 없었습니다. 모델을 변경하면 직접 SQL을 작성해서 ALTER TABLE을 실행해야 했습니다. 이를 해결하기 위해 South라는 서드파티 라이브러리가 등장했습니다(2008).

Django 1.7(2014)에서 South의 핵심 개발자가 Django 코어 팀에 합류하며 공식 마이그레이션 시스템이 내장되었습니다. 이제 makemigrationsmigrate 명령으로 스키마 변경을 자동화할 수 있습니다.


1. Django 시작하기

설치 및 프로젝트 생성

startproject웹 사이트 전체를 감쌀 큰 상자를 만들으며, startapp은 그 안에 기능 단위(예: 블로그, 결제) 모듈을 하나씩 추가하는 과정입니다. 이후 models.py는 DB 테이블 모양을, views.py는 요청 처리 순서를, templates는 화면 HTML을 담당합니다.

# Django 설치
pip install django
# 프로젝트 생성
django-admin startproject myproject
cd myproject
# 앱 생성
python manage.py startapp blog
# 개발 서버 실행
python manage.py runserver

프로젝트 구조

myproject/
├── myproject/
│   ├── __init__.py
│   ├── settings.py  # 설정
│   ├── urls.py      # URL 라우팅
│   └── wsgi.py
├── blog/
│   ├── models.py    # 모델 (데이터)
│   ├── views.py     # 뷰 (로직)
│   ├── urls.py
│   └── templates/   # 템플릿 (화면)
└── manage.py

2. 모델 (Model)

모델 정의

# blog/models.py
from django.db import models
class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.title
    
    class Meta:
        ordering = ['-created_at']

마이그레이션

# 마이그레이션 파일 생성
python manage.py makemigrations
# 데이터베이스에 적용
python manage.py migrate

3. 뷰 (View)

함수 기반 뷰

# blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
    posts = Post.objects.all()
    return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

클래스 기반 뷰

from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
    model = Post
    template_name = 'blog/post_list.html'
    context_object_name = 'posts'
    paginate_by = 10
class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'

4. URL 라우팅

URL 패턴

# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
    path(', views.post_list, name='post_list'),
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
# myproject/urls.py
# 필요한 모듈 import
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),
]

5. 템플릿

템플릿 작성

<!-- templates/blog/post_list.html -->
<!DOCTYPE html>
<html>
<head>
    <title>블로그</title>
</head>
<body>
    <h1>블로그 포스트</h1>
    
    {% for post in posts %}
        <article>
            <h2>
                <a href="{% url 'blog:post_detail' post.pk %}">
                    {{ post.title }}
                </a>
            </h2>
            <p>{{ post.content|truncatewords:30 }}</p>
            <small>{{ post.created_at|date:"Y-m-d H:i" }}</small>
        </article>
    {% empty %}
        <p>포스트가 없습니다.</p>
    {% endfor %}
</body>
</html>

6. Admin 사이트

Admin 등록

# blog/admin.py
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'created_at']
    list_filter = ['created_at', 'author']
    search_fields = ['title', 'content']
    date_hierarchy = 'created_at'

슈퍼유저 생성

python manage.py createsuperuser
# Username: admin
# Email: admin@example.com
# Password: ****
# http://localhost:8000/admin/ 접속

7. 실전 예제

간단한 블로그

# blog/views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .models import Post
def create_post(request):
    if request.method == 'POST':
        title = request.POST.get('title')
        content = request.POST.get('content')
        author = request.POST.get('author')
        
        Post.objects.create(
            title=title,
            content=content,
            author=author
        )
        
        messages.success(request, '포스트가 생성되었습니다!')
        return redirect('blog:post_list')
    
    return render(request, 'blog/create_post.html')

정리

핵심 요약

  1. Django: 풀스택 웹 프레임워크
  2. MVT: Model, View, Template
  3. ORM: Python 코드로 DB 조작
  4. Admin: 자동 관리자 페이지
  5. 마이그레이션: 데이터베이스 스키마 관리

다음 단계


관련 글


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Django 기초: Python 풀스택 웹 프레임워크 시작하기. Django 시작하기·모델 (Model)로 흐름을 잡고 원리·코드·실무 적용을 한글로 정리합니다. Python·Django·웹개발 중심으로 설명합니다.… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. Python 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

Python, Django, 웹개발, 백엔드, ORM, MVT, 프레임워크 등으로 검색하시면 이 글이 도움이 됩니다.