The Web framework for perfectionists with deadlines
'마감일이 있는 완벽주의자를 위한 웹 프레임워크' Django의 특징을 명확하게 보여주는 모토입니다. 실제로 다른 웹 프레임워크를 사용해본 분이라면, 후술할 특징들을 보면서 개발 생산성만큼은 정말 좋다는 것을 이해할 겁니다.
Django의 특징으로는 배터리 포함, 관례보다는 명시적인 설정이라고 할 수 있습니다.
배터리 포함은 웹 개발에 필요한 사용자 인증, ORM, 관리자 인터페이스, 보안 기능, 캐싱, 세션 관리 등이 모두 기본 내장되어 있어 별도의 라이브러리 설치 없이도 완전한 웹 애플리케이션을 구축할 수 있음을 의미합니다.
명시적인 설정은 Django가 "명시적인 것이 암시적인 것보다 낫다(Explicit is better than implicit)"는 Python의 철학을 따라, 매직이나 숨겨진 동작보다는 코드에서 명확하게 동작을 정의하고 설정을 명시적으로 작성하도록 장려함을 뜻합니다.
DRF(Django Rest Framework)는 Django의 "배터리 포함" 철학을 API 개발로 확장한, 브라우저에서 바로 테스트 가능한 RESTful API 구축 도구입니다.
얼마나 간단한지 보여드리자면 이렇게 유저에 대한 CRUD가 모두 완성되었습니다.
이제 비즈니스 요구사항에 따라 로직을 어떻게 더 넣을지만 고민하면 됩니다.
from rest_framework import viewsets, serializers
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'date_joined']
read_only_fields = ['id', 'date_joined']
# 단 몇 줄로 완전한 CRUD API 완성
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated]
Django는 웹 개발에 필요한 거의 모든 것을 기본 제공합니다. 사용자 인증, ORM, 세션 관리, 캐싱, 메일 발송, 페이지네이션, API 문서화까지 모두 내장되어 있는것이 좋습니다. Spring Boot의 경우 엔터프라이즈급 기능을 위해서는 여러 스타터 의존성을 추가해야 하고, NestJS는 대부분의 핵심 기능에 외부 라이브러리가 필요합니다. 하지만 Django는 pip install django만 하면 바로 완전한 웹 애플리케이션이 만들 수 있습니다. 검증된 내장 기능들을 사용하면 버그 발생 가능성도 줄어들고, 팀원들이 도구를 다시 만드는데 시간을 소모하지 않아도 됩니다.
개인적으로 가장 감동받은 부분입니다. Django는 User 객체가 이미 완벽하게 구현되어 있습니다. 회원가입, 로그인, 권한 관리, 비밀번호 암호화, 세션 관리까지 모든 것이 준비되어 있습니다. 다른 프레임워크들은 사용자 인증 시스템을 직접 구현하거나 외부 라이브러리를 연동해야 하는데, 이 과정에서 보안 취약점이 생기기 쉽습니다. Django의 User 모델은 years of battle-testing을 거쳐 안전하고 확장 가능하게 설계되었습니다. 필요하면 AbstractUser나 AbstractBaseUser를 상속받아 커스터마이징도 쉽게 할 수 있어요. 실제로 프로젝트를 시작하자마자 로그인 기능이 작동하는 걸 보면, 정말 개발자 경험이 다르다는 걸 느낄 수 있습니다.
DRF의 가장 큰 강점 중 하나는 필요에 따라 추상화 레벨을 자유롭게 조정할 수 있다는 점입니다. 간단한 CRUD 작업은 ModelViewSet으로 몇 줄만 작성하면 되고, 복잡한 비즈니스 로직이 필요한 부분은 Function-based View나 APIView로 세밀하게 제어할 수 있습니다. 심지어 같은 프로젝트 내에서도 app마다 다른 추상화 레벨을 적용할 수 있습니다. 예를 들어, 사용자 관리는 높은 추상화로 빠르게 구현하고, 결제 로직은 낮은 추상화로 안전하게 작성할 수 있죠. 이런 유연성 덕분에 프로토타이핑 단계에서는 빠르게 개발하고, 나중에 필요한 부분만 점진적으로 세밀하게 다듬어갈 수 있습니다. Spring이나 NestJS는 처음부터 구조를 잘 설계해야고 정해진 원칙을 지켜야하는 부담이 있지만, Django는 일단 빠르게 만들고 나중에 리팩토링하기가 훨씬 수월합니다.
| 관심사 | Spring | Django | DRF | NestJS |
|---|---|---|---|---|
| HTTP 처리 | Controller | View | ViewSet/APIView | Controller |
| 비즈니스 로직 | Service | View/Model | ViewSet/Service | Service |
| 데이터 검증 | Validator | Form | Serializer | DTO + Validator |
| 데이터 변환 | DTO | - | Serializer | DTO |
| 데이터 접근 | Repository | Model | Model | Repository/Entity |
| 권한 관리 | Security Config | Decorator | Permission | Guard |
| 필터링 | Specification | Manager | FilterSet | Query Builder |
웹 개발을 시작하면서 가장 혼란스러운 것 중 하나가 바로 프레임워크마다 다른 용어와 개념입니다. 같은 기능을 하는데 Spring에서는 'Controller', Django에서는 'View', NestJS에서는 다시 'Controller'라고 부릅니다.
위 표는 각 프레임워크가 동일한 관심사를 어떤 방식으로 구현하고 명명하는지를 정리한 것입니다. 이런 용어의 차이 때문에 새로운 프레임워크를 배울 때 학습 곡선이 생기는 것 같습니다. 하지만 본질적인 관심사는 동일하다는 것을 알면, 한 프레임워크에서 다른 프레임워크로 넘어가는 것이 훨씬 수월해집니다.
앞으로 설명할 Django의 장점들을 읽으면서 이해가 안 되는 부분이 있다면, 이 표를 참고해서 다른 프레임워크의 해당 개념과 연결해서 생각해보시면 됩니다.
Django는 MTV (Model-Template-View) 패턴을 따릅니다. 이는 전통적인 MVC 패턴을 Django만의 방식으로 해석한 것으로, 각 구성 요소가 명확한 역할을 분담하여 코드의 구조를 체계적으로 관리합니다.
Django 개발자들이 MTV 명명법을 선택한 이유는 웹 개발의 특성을 더 명확하게 반영하기 위함이었습니다. Django 공식 문서에 따르면, Django에서 "view"는 사용자에게 제시되는 데이터를 설명하는 것이지, 데이터가 어떻게 보이는지가 아니라 어떤 데이터를 보여주는지에 관한 것입니다. 이는 미묘한 차이이지만, View는 특정 URL에 대한 Python 콜백 함수이며, 해당 콜백 함수가 어떤 데이터가 제시되는지를 설명하기 때문입니다.
전통적인 MVC에서 "View"는 사용자 인터페이스(UI)를 의미하지만, Django에서는 "어떤 데이터를 보여줄지 결정하는 로직"을 View라고 부르고, 실제 화면 표시는 Template이 담당합니다. 하지만 이런 독특한 명명법이 오히려 혼란을 야기했다는 비판도 있어, 한 Django 개발자는 "우리가 다른 모든 프레임워크와 같은 용어를 사용하지 않아서 사실 많은 혼란을 초래했다"고 인정하기도 했습니다. 결국 Django의 MTV는 웹 개발의 특성상 "데이터 로직(Model) → 비즈니스 로직(View) → 화면 표시(Template)"라는 흐름을 더 직관적으로 표현하려 했지만, 기존 MVC 패턴에 익숙한 개발자들에게는 오히려 학습 장벽이 되었다는 것이 역설적입니다.


Django REST Framework를 처음 배우는 개발자들이 가장 어려워하는 부분은 바로 각 컴포넌트의 역할과 데이터 흐름을 이해하는 것입니다. 전통적인 웹 개발에서는 단순히 "요청 → 처리 → 응답"이었다면, DRF에서는 URL Router → View → Serializer → Model → Database 그리고 다시 역순으로 돌아오는 복잡한 흐름을 가집니다. 특히 Serializer의 역할이 혼란스러운데, 이는 데이터 검증, 직렬화, 역직렬화를 모두 담당하면서 View와 Model 사이에서 중간 다리 역할을 하기 때문입니다. 많은 초보자들이 "왜 이렇게 복잡하게 나누어야 하는가?"라고 의문을 가지지만, 실제로는 각 계층이 명확한 책임을 가지고 있어 한 번 익숙해지면 코드의 재사용성과 유지보수성이 극적으로 향상됩니다. 이 흐름도를 이해하는 것이 Django 학습의 핵심이며, 각 단계에서 무엇이 일어나는지 파악하면 복잡해 보이는 DRF도 사실은 매우 논리적이고 체계적인 구조임을 알 수 있습니다.
앞으로 제시하는 각 컴포넌트의 개념을 이해하고, 흐름이 어떻게 진행되는지 이해하면 금새 django의 구조를 배울 수 있습니다.
URLs (URL Router)는 WSGI 서버가 Django 애플리케이션으로 전달한 HTTP 요청을 적절한 View로 연결하는 중간 매개체 역할을 합니다. WSGI가 Postman이나 브라우저에서 들어오는 HTTP 요청을 Django로 전달하면, Router는 URL 패턴을 분석하고 해당하는 View로 요청을 라우팅합니다. DRF의 Router는 Rails에서 영감을 받아 자동 URL 라우팅을 Django에 추가한 것으로, ViewSet 하나를 등록하면 자동으로 여러 URL 패턴을 생성합니다. 예를 들어 router.register(r'presentations', PresentationViewSet)라고 등록하면 자동으로 /presentations/ (목록), /presentations/1/ (상세) 등의 URL이 생성되며, Router가 이를 해석해서 PresentationViewSet의 적절한 메서드로 라우팅하고 URL에서 추출한 매개변수도 함께 전달합니다.
Views는 실제 비즈니스 로직이 처리되는 핵심 공간입니다. HTTP 메서드(GET, POST, PUT, DELETE)에 따라 적절한 동작을 수행하며, 권한 검사, 인증 확인, 쿼리 필터링 등의 작업을 담당합니다. DRF는 다양한 종류의 View를 제공하는데, 가장 기본적인 APIView는 Django의 일반 View와 달리 Request/Response 객체를 사용하고 인증, 권한, 예외 처리를 자동으로 처리합니다. 더 고수준의 ViewSet을 사용하면 CRUD 작업이 자동으로 구현되지만, 복잡한 비즈니스 로직이 필요한 경우 APIView나 커스텀 메서드를 추가할 수 있어 확장성이 뛰어납니다. ViewSet은 Router와 연동되어 하나의 클래스만으로도 여러 엔드포인트를 한 번에 생성할 수 있어, 개발 속도를 크게 향상시킵니다.
Serializer는 API 개발에서 핵심적인 세 가지 역할을 담당합니다:
Django 모델 객체를 JSON으로 변환하는 과정입니다. 데이터베이스에서 가져온 Python 객체를 클라이언트(브라우저, 앱)가 이해할 수 있는 JSON 형태로 바꿔줍니다. Serializer는 모델의 각 필드를 적절한 JSON 형태로 자동 변환하며, 날짜는 ISO 형식으로, 외래키는 관련 객체의 표현으로 변환합니다.
# Python 객체 → JSON 변환
presentation = Presentation.objects.get(id=1)
serializer = PresentationSerializer(presentation)
json_data = serializer.data
# 결과: {"id": 1, "title": "Django 소개", "presenter_name": "홍길동"}
클라이언트가 보낸 JSON 데이터를 Django 모델 객체로 변환하는 과정입니다. API로 받은 데이터를 데이터베이스에 저장할 수 있는 형태로 바꿔줍니다. 이 과정에서 Serializer는 JSON의 각 필드를 Python 객체의 적절한 타입으로 변환하고, 관계형 데이터도 올바르게 연결해줍니다.
# JSON → Python 객체 변환
json_data = {"title": "FastAPI vs Django", "description": "성능 비교"}
serializer = PresentationSerializer(data=json_data)
if serializer.is_valid():
presentation = serializer.save() # 데이터베이스에 저장
입력 데이터가 올바른지 자동으로 검사합니다. 필수 필드 누락, 데이터 타입 오류, 커스텀 비즈니스 규칙 위반 등을 체크합니다. Django 모델의 제약조건뿐만 아니라 필드별, 객체별 커스텀 검증 로직도 실행하여 잘못된 데이터가 데이터베이스에 저장되는 것을 방지합니다.
class PresentationSerializer(serializers.ModelSerializer):
class Meta:
model = Presentation
fields = ['title', 'description', 'duration']
def validate_duration(self, value):
if value < 5 or value > 60:
raise serializers.ValidationError("발표 시간은 5-60분 사이여야 합니다.")
return value
1. Serializer (기본 클래스): 모든 필드를 수동으로 정의해야 하지만 완전한 제어가 가능합니다. 복잡한 비즈니스 로직이나 Django 모델이 아닌 데이터를 다룰 때 사용합니다.
2. ModelSerializer: Django 모델로부터 자동으로 필드를 생성해주는 가장 많이 사용되는 Serializer입니다. 모델의 필드 타입에 따라 적절한 Serializer 필드를 자동 매핑하고, create()와 update() 메서드도 기본 제공합니다.
3. HyperlinkedModelSerializer: 관계를 기본 키 대신 하이퍼링크로 표현하여 RESTful API 설계 원칙에 더 부합합니다. API 응답에 관련 리소스로의 직접 링크를 포함하여 클라이언트가 쉽게 탐색할 수 있게 합니다.
4. ListSerializer: 여러 객체를 한 번에 처리할 때 사용됩니다. many=True 옵션을 사용할 때 자동으로 생성되며, 대량 생성이나 업데이트 작업을 효율적으로 처리할 수 있습니다.
5. BaseSerializer: 완전히 커스텀한 직렬화 로직이 필요할 때 사용하는 최상위 클래스입니다. to_representation()과 to_internal_value() 메서드를 직접 구현하여 특수한 데이터 형태를 처리할 수 있습니다.
Serializer가 개발자 생산성을 크게 향상시키는 이유는 복잡한 데이터 변환과 검증 작업을 자동화하기 때문입니다. ModelSerializer를 사용하면 단 몇 줄의 코드로 완전한 API 직렬화 로직이 완성되며, Django Form과 유사한 친숙한 문법으로 학습 곡선을 낮춥니다. 또한 필드별 검증, 중첩된 객체 처리, 부분 업데이트 등의 고급 기능을 기본 제공하여 개발자가 반복적인 boilerplate 코드 작성 대신 핵심 비즈니스 로직에 집중할 수 있게 해줍니다. 특히 DRF의 브라우저 API 인터페이스와 연동되어 별도의 API 테스트 도구 없이도 즉시 테스트가 가능하여, 개발과 디버깅 속도를 대폭 향상시킵니다.
Model은 데이터베이스와 Django 애플리케이션을 연결하는 핵심 브리지 역할을 담당합니다. Model은 데이터에 대한 단일하고 명확한 정보 소스로, 저장하고 있는 데이터의 필수 필드와 동작을 포함합니다. 일반적으로 각 모델은 단일 데이터베이스 테이블에 매핑됩니다. Django의 Model은 단순한 데이터 저장소를 넘어서 비즈니스 로직을 캡슐화하고, 데이터 검증 규칙을 정의하며, 관계를 설정하는 도메인 객체의 역할을 합니다.
1. 데이터베이스 테이블 정의: 각 모델은 django.db.models.Model을 상속하는 Python 클래스이며, 모델의 각 속성은 데이터베이스 필드를 나타냅니다. 예를 들어 CharField는 VARCHAR, IntegerField는 INTEGER 컬럼으로 자동 변환됩니다.
2. ORM 인터페이스 제공: Django는 자동으로 생성된 데이터베이스 접근 API를 제공합니다. 복잡한 SQL 쿼리를 작성하지 않고도 User.objects.filter(email='test@example.com')처럼 Python 코드로 데이터를 조작할 수 있습니다.
3. 데이터 검증과 제약조건: 필드 타입에 따라 데이터베이스에 저장할 데이터 종류를 결정하고, Django의 관리자와 자동 생성 폼에서 사용되는 최소 검증 요구사항을 정의합니다. max_length, null, blank 등의 옵션으로 세밀한 제약조건을 설정할 수 있습니다.
관계 정의: Django는 가장 일반적인 세 가지 데이터베이스 관계인 다대일, 다대다, 일대일 관계를 정의하는 방법을 제공합니다. ForeignKey, ManyToManyField, OneToOneField를 통해 복잡한 데이터 관계를 직관적으로 표현할 수 있습니다.
커스텀 메서드와 프로퍼티: 모델에 커스텀 메서드를 정의하여 객체에 커스텀 "행 수준" 기능을 추가할 수 있으며, 이는 비즈니스 로직을 한 곳에 유지하는 값진 기술입니다. 예를 들어 full_name 프로퍼티로 이름과 성을 조합하거나, is_adult() 메서드로 나이 기반 로직을 캡슐화할 수 있습니다.
상속과 확장성: Django Model은 추상 베이스 클래스, 다중 테이블 상속, 프록시 모델 등 다양한 상속 패턴을 지원하여 코드 재사용성과 확장성을 극대화합니다.
Model이 개발자 생산성을 혁신적으로 향상시키는 이유는 복잡한 데이터베이스 작업을 Python 코드로 추상화하기 때문입니다. SQL을 직접 작성하지 않아도 되고, 테이블 스키마 변경은 마이그레이션으로 자동화되며, Django Admin을 통해 즉시 관리 인터페이스가 생성됩니다. 특히 Django의 "Convention over Configuration" 철학이 빛을 발하는 부분으로, 최소한의 코드 작성만으로도 완전한 데이터베이스 레이어가 구축되어 개발자가 핵심 비즈니스 로직에 집중할 수 있게 해줍니다.
먼저 프로젝트 환경을 설정하고 어떤 폴더 구조가 만들어지는지 살펴보겠습니다.
# Django 프로젝트 생성
django-admin startproject pythings
cd pythings
# 앱 생성
python manage.py startapp presentations
python manage.py startapp events
위 명령어들을 실행하면 다음과 같은 폴더 구조가 생성됩니다:
pythings/
├── manage.py
├── pythings/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── presentations/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── views.py
│ └── migrations/
└── events/
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── views.py
└── migrations/
Django는 프로젝트와 앱이라는 개념으로 구성됩니다.
프로젝트는 전체 웹사이트를 의미하고, 앱은 특정 기능을 담당하는 모듈입니다. 예를 들어 presentations 앱은 발표 관련 기능만, events 앱은 이벤트 관련 기능만 담당하죠. 이렇게 기능별로 분리하면 코드 관리가 훨씬 쉬워집니다.
PyThing 플랫폼은 간단한 구조입니다:
하나의 Event에는 여러 개의 Presentation이 속할 수 있는 1:다 관계입니다.
Models는 데이터베이스의 테이블을 Python 클래스로 표현하는 것입니다. 테이블의 컬럼은 클래스의 필드가 되죠.
python
# presentations/models.py
from django.db import models
from django.contrib.auth.models import User
class Presentation(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
presenter = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
# events/models.py
from django.db import models
from presentations.models import Presentation
class Event(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField()
location = models.CharField(max_length=100)
def __str__(self):
return self.title
# 비즈니스 로직은 나중에 추가 가능
def get_presentation_count(self):
return self.presentations.count()
def is_upcoming(self):
from django.utils import timezone
return self.date > timezone.now()
Django의 User 모델은 이미 완벽하게 구현되어 있어 바로 사용할 수 있습니다. 로그인, 권한, 비밀번호 관리까지 모든 기능이 내장되어 있어요.
새로 만든 앱들을 Django에 등록해야 합니다.
# pythings/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # DRF 추가
'presentations', # 우리가 만든 앱들
'events',
]
Django의 앱(App) 개념은 기능별 모듈화입니다. 각 앱은 독립적으로 동작하며, 다른 프로젝트에서도 재사용할 수 있어요. 예를 들어 presentations 앱은 다른 교육 플랫폼에서도 그대로 사용할 수 있습니다.
마이그레이션은 Python 코드로 작성한 모델을 실제 데이터베이스 테이블로 변환하는 과정입니다.
# 마이그레이션 파일 생성 (설계도 만들기)
python manage.py makemigrations
# 마이그레이션 적용 (실제 테이블 생성)
python manage.py migrate
마이그레이션은 데이터베이스 변경사항을 추적하고 버전 관리하는 시스템입니다. 모델을 수정하면 새로운 마이그레이션을 만들어서 기존 데이터를 보존하면서 테이블 구조를 변경할 수 있어요.
Serializer는 API 개발에서 핵심적인 세 가지 역할을 담당합니다:
Django 모델 객체를 JSON으로 변환하는 과정입니다. 데이터베이스에서 가져온 Python 객체를 클라이언트(브라우저, 앱)가 이해할 수 있는 JSON 형태로 바꿔줍니다.
# Python 객체 → JSON 변환
presentation = Presentation.objects.get(id=1)
serializer = PresentationSerializer(presentation)
json_data = serializer.data
# 결과: {"id": 1, "title": "Django 소개", "presenter_name": "홍길동"}
클라이언트가 보낸 JSON 데이터를 Django 모델 객체로 변환하는 과정입니다. API로 받은 데이터를 데이터베이스에 저장할 수 있는 형태로 바꿔줍니다.
# JSON → Python 객체 변환
json_data = {"title": "FastAPI vs Django", "description": "성능 비교"}
serializer = PresentationSerializer(data=json_data)
if serializer.is_valid():
presentation = serializer.save() # 데이터베이스에 저장
입력 데이터가 올바른지 자동으로 검사합니다. 필수 필드 누락, 데이터 타입 오류, 커스텀 비즈니스 규칙 위반 등을 체크합니다.
class PresentationSerializer(serializers.ModelSerializer):
class Meta:
model = Presentation
fields = ['title', 'description', 'duration']
def validate_duration(self, value):
if value < 5 or value > 60:
raise serializers.ValidationError("발표 시간은 5-60분 사이여야 합니다.")
return value
View는 이름과는 좀 다르게 실제 API 엔드포인트를 만드는 곳입니다. HTTP 요청을 받아서 처리하고 응답을 반환합니다.
# presentations/views.py
from rest_framework import viewsets
from .models import Presentation
from .serializers import PresentationSerializer
class PresentationViewSet(viewsets.ModelViewSet):
queryset = Presentation.objects.all()
serializer_class = PresentationSerializer
# 비즈니스 로직 추가 예시
def get_queryset(self):
queryset = super().get_queryset()
# 내 발표만 보기 필터
if self.request.query_params.get('my_only'):
queryset = queryset.filter(presenter=self.request.user)
return queryset
# events/views.py
from rest_framework import viewsets
from .models import Event
from .serializers import EventSerializer
class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
ViewSet은 CRUD 작업을 자동으로 만들어줍니다. 단 몇 줄의 코드로 생성(POST), 조회(GET), 수정(PUT), 삭제(DELETE) API가 모두 완성됩니다.
urls.py는 URL과 View를 연결하는 라우터 역할을 합니다. 어떤 URL로 요청이 오면 어떤 View가 처리할지 결정합니다.
python
# pythings/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from presentations.views import PresentationViewSet
from events.views import EventViewSet
router = DefaultRouter()
router.register(r'presentations', PresentationViewSet)
router.register(r'events', EventViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
]
DRF의 Router는 ViewSet으로부터 자동으로 URL 패턴을 생성합니다. 위 코드로 다음과 같은 엔드포인트들이 자동 생성됩니다:
GET /api/presentations/ - 발표 목록 조회POST /api/presentations/ - 새 발표 생성GET /api/presentations/1/ - 특정 발표 조회PUT /api/presentations/1/ - 특정 발표 수정DELETE /api/presentations/1/ - 특정 발표 삭제# 개발 서버 실행
python manage.py runserver
# 브라우저에서 확인
# http://127.0.0.1:8000/api/
이게 바로 Django의 매력입니다. 몇 개의 간단한 파일만 작성했는데 완전한 REST API가 완성되었어요. 자동 API 문서화, 브라우저에서 바로 테스트 가능한 인터페이스까지 모든 기능이 작동합니다.