Django Complete Guide | MTV· ORM
이 글의 핵심
Django is Python's 'batteries included' web framework — used by Instagram, Pinterest, and Mozilla. This guide covers everything from project setup to production deployment, including the built-in Admin panel and Django REST Framework.
Why Django?
Django’s philosophy is “don’t repeat yourself” and “batteries included”. It ships with everything a web application needs:
- ORM — write Python instead of SQL; automatic migrations
- Admin panel — auto-generated CRUD interface from your models
- Auth system — users, groups, permissions, sessions built in
- Security — CSRF, XSS, SQL injection protection by default
- REST Framework — best-in-class API layer (separate package)
Flask: ~1,000 req/sec (minimal, build everything yourself)
Django: ~800 req/sec (full-stack, batteries included)
FastAPI: ~3,000 req/sec (API-only, async)
Installation & Project Setup
pip install django
django-admin startproject myproject
cd myproject
python manage.py runserver
# → http://localhost:8000
Create an app (Django organizes code into apps):
python manage.py startapp users
Register your app in settings.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ...
'users', # Your new app
]
Project structure:
myproject/
├── manage.py # Command-line utility
├── myproject/
│ ├── settings.py # Configuration
│ ├── urls.py # Root URL configuration
│ └── wsgi.py # WSGI entry point
└── users/
├── models.py # Database models
├── views.py # Request handlers
├── urls.py # App URL patterns
├── admin.py # Admin registration
└── tests.py # Unit tests
Models — Define Your Database Schema
Django models map directly to database tables. No SQL needed.
# users/models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
age = models.IntegerField(null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at'] # Newest first by default
def __str__(self):
return self.name
Apply the schema to your database:
python manage.py makemigrations # Generate migration files
python manage.py migrate # Apply to the database
ORM Queries
# Create
user = User.objects.create(name="Alice", email="alice@example.com")
# Read
all_users = User.objects.all()
active_users = User.objects.filter(is_active=True)
alice = User.objects.get(email="alice@example.com") # Raises if not found
# Update
User.objects.filter(id=1).update(is_active=False)
# Delete
User.objects.filter(is_active=False).delete()
# Chaining
recent_active = (
User.objects
.filter(is_active=True)
.order_by('-created_at')
[:10] # SQL LIMIT 10
)
Views — Handle HTTP Requests
Function-Based Views (FBV)
# users/views.py
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .models import User
@require_http_methods(["GET"])
def user_list(request):
users = User.objects.all().values('id', 'name', 'email')
return JsonResponse(list(users), safe=False)
@require_http_methods(["GET"])
def user_detail(request, user_id):
try:
user = User.objects.get(id=user_id)
return JsonResponse({
'id': user.id,
'name': user.name,
'email': user.email,
})
except User.DoesNotExist:
return JsonResponse({'error': 'User not found'}, status=404)
Class-Based Views (CBV)
Django’s generic CBVs reduce boilerplate for common patterns:
from django.views.generic import ListView, DetailView, CreateView
from django.urls import reverse_lazy
class UserListView(ListView):
model = User
template_name = 'users/list.html'
context_object_name = 'users'
paginate_by = 10 # Auto-pagination
class UserDetailView(DetailView):
model = User
template_name = 'users/detail.html'
context_object_name = 'user'
class UserCreateView(CreateView):
model = User
fields = ['name', 'email', 'age']
success_url = reverse_lazy('user_list') # Redirect after creation
URL Configuration
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.user_list, name='user_list'),
path('<int:user_id>/', views.user_detail, name='user_detail'),
]
Include app URLs in the root configuration:
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/users/', include('users.urls')),
]
Django REST Framework (DRF)
DRF is the standard way to build REST APIs with Django. Install it:
pip install djangorestframework
Add to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
'rest_framework',
'users',
]
Serializer — JSON ↔ Python Object Conversion
# users/serializers.py
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'email', 'age', 'is_active', 'created_at']
read_only_fields = ['id', 'created_at']
ViewSet — CRUD in One Class
A ModelViewSet automatically provides list, create, retrieve, update, and destroy endpoints:
# users/views.py
from rest_framework import viewsets, permissions
from .models import User
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
# Optional: filter by query param (?active=true)
qs = super().get_queryset()
if self.request.query_params.get('active'):
qs = qs.filter(is_active=True)
return qs
Router — Auto-Generate URLs
# users/urls.py
from rest_framework.routers import DefaultRouter
from .views import UserViewSet
router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls
# Generates:
# GET/POST /users/
# GET/PUT/PATCH/DELETE /users/{id}/
Admin Panel
Django’s admin panel is auto-generated from your models. Customize it:
# users/admin.py
from django.contrib import admin
from .models import User
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'email', 'is_active', 'created_at']
list_filter = ['is_active', 'created_at']
search_fields = ['name', 'email']
ordering = ['-created_at']
list_per_page = 25
readonly_fields = ['created_at', 'updated_at']
Create a superuser and log in:
python manage.py createsuperuser
# → http://localhost:8000/admin
The admin panel gives your team a full CRUD interface with search, filtering, and pagination — zero frontend code required.
Authentication
Built-in Session Auth
from django.contrib.auth.decorators import login_required
@login_required # Redirects to /login/ if not authenticated
def protected_view(request):
return JsonResponse({'user': request.user.username})
JWT Authentication (for APIs)
pip install djangorestframework-simplejwt
Configure DRF to use JWT:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
Add token endpoints:
# urls.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path('api/token/', TokenObtainPairView.as_view()), # POST → access + refresh tokens
path('api/token/refresh/', TokenRefreshView.as_view()), # POST → new access token
]
Usage:
# Get tokens
curl -X POST http://localhost:8000/api/token/ \
-d '{"username": "alice", "password": "secret"}'
# → {"access": "eyJ...", "refresh": "eyJ..."}
# Use the access token
curl http://localhost:8000/api/users/ \
-H "Authorization: Bearer eyJ..."
Deployment
Gunicorn (Production WSGI Server)
pip install gunicorn
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 4
Docker
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "4"]
Production Settings Checklist
# settings_production.py
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
}
}
STATIC_ROOT = '/var/www/static/'
SECRET_KEY = os.environ['SECRET_KEY']
Summary
| Feature | Django |
|---|---|
| Admin panel | Auto-generated from models |
| ORM | Python queries → any SQL database |
| Auth | Users, groups, permissions built in |
| REST API | Via Django REST Framework |
| Security | CSRF, XSS, SQL injection — default |
| Scale | Instagram (1B+ users) proves it |
Django’s biggest win is speed of development — the Admin panel alone eliminates weeks of backoffice UI work. Use it when you need a complete web application, not just an API.
Related posts:
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Build full-stack web applications with Django. Covers project setup, Models/ORM, Views, URL routing, Admin panel, Django…
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- FastAPI 완벽 가이드 — Python 최고 성능 웹 프레임워크, Django·Flask 대체
- Docker & Kubernetes 입문 가이드 | 컨테이너부터 오케스트레이션까지
Keywords Covered in This Article (Related Search Terms)
This article covers Django, Python, Backend, MTV, ORM, REST API, Full Stack.