출시·고도화 중
Django 안내서 · 3/6
Django로 만든 사이트는 요청 하나가 들어오면 미들웨어를 거쳐 URLconf에서 뷰를 찾고, 뷰가 모델로 데이터를 읽어 템플릿으로 응답을 만드는 흐름으로 움직입니다. 이 장에서는 이 흐름을 이루는 MTV 구조, URLconf, 앱, 관리자 화면, 미들웨어, 설정을 차례로 살펴봅니다.
Django는 역할을 셋으로 나눕니다.
| 구성 요소 | 맡는 일 |
|---|---|
| 모델(Model) | 데이터의 구조와 규칙. 데이터베이스 테이블과 대응 |
| 템플릿(Template) | 데이터를 HTML 등으로 보여 주는 방식 |
| 뷰(View) | 요청을 받아 필요한 데이터를 모으고 응답을 결정 |
다른 프레임워크의 MVC에서 컨트롤러가 하는 일은 Django에서 뷰와 URLconf가 나눠 맡습니다. 간단한 모델 하나를 예로 들어 보겠습니다.
# polls/models.py
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("공개일")
def __str__(self):
return self.question_text뷰는 HttpRequest를 받아 HttpResponse를 돌려주는 함수(또는 클래스)입니다. render()는 템플릿에 컨텍스트를 넣어 응답을 만들고, get_object_or_404()는 객체가 없으면 404 응답을 냅니다.
# polls/views.py
from django.shortcuts import get_object_or_404, render
from .models import Question
def index(request):
latest = Question.objects.order_by("-pub_date")[:5]
return render(request, "polls/index.html", {"latest": latest})
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})템플릿 언어는 {{ 변수 }}로 값을 출력하고 {% 태그 %}로 반복·조건·상속을 표현합니다. 출력하는 값은 자동으로 HTML 이스케이프되어 XSS를 막습니다.
{% extends "base.html" %}
{% block content %}
<h1>최근 질문</h1>
<ul>
{% for question in latest %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% empty %}
<li>아직 질문이 없습니다.</li>
{% endfor %}
</ul>
{% endblock %}반복되는 패턴은 클래스 기반 뷰(class-based view)로 줄일 수 있습니다. ListView, DetailView, CreateView 같은 제네릭 뷰는 목록·상세·생성 화면을 몇 줄로 만들어 줍니다.
from django.views import generic
from .models import Question
class DetailView(generic.DetailView):
model = Question
template_name = "polls/detail.html"URLconf는 URL 패턴과 뷰를 잇는 목록입니다. path()의 <int:question_id> 같은 변환기는 URL 일부를 잘라 뷰의 인자로 넘깁니다. 이름(name)을 붙여 두면 코드에서는 reverse("polls:detail", args=[1]), 템플릿에서는 {% url %} 태그로 주소를 만들 수 있어, URL이 바뀌어도 링크를 고칠 필요가 없습니다.
# polls/urls.py
from django.urls import path
from . import views
app_name = "polls"
urlpatterns = [
path("", views.index, name="index"),
path("<int:question_id>/", views.detail, name="detail"),
path("q/<int:pk>/", views.DetailView.as_view(), name="question"),
]app_name은 URL 이름공간입니다. 여러 앱에 index라는 이름이 있어도 polls:index처럼 구분할 수 있습니다.
앱은 모델·뷰·템플릿·URL을 묶은 재사용 가능한 단위입니다. 앱은 INSTALLED_APPS에 등록해야 모델·템플릿·관리 명령이 인식됩니다. apps.py의 AppConfig에서 앱 이름을 정하고, ready() 메서드에서 시그널 연결처럼 시작할 때 한 번 할 일을 처리합니다. django.contrib.auth, django.contrib.admin도 같은 방식으로 들어 있는 앱입니다.
admin.py에 모델을 등록하면 /admin/에서 목록·검색·편집 화면을 바로 쓸 수 있습니다. ModelAdmin으로 목록 열, 필터, 검색 필드를 정합니다.
# polls/admin.py
from django.contrib import admin
from .models import Question
@admin.register(Question)
class QuestionAdmin(admin.ModelAdmin):
list_display = ["question_text", "pub_date"]
list_filter = ["pub_date"]
search_fields = ["question_text"]관리자 화면은 내부 직원용 도구로 설계되었습니다. 일반 사용자에게 보여 줄 화면은 뷰와 템플릿으로 따로 만드는 것이 원칙입니다.
미들웨어는 모든 요청과 응답을 감싸는 층입니다. 세션, 인증, CSRF 검사, 보안 헤더가 모두 미들웨어로 동작하며, MIDDLEWARE 목록의 위에서 아래 순서로 요청을 처리하고 응답은 반대 순서로 지나갑니다. 직접 만들 때는 get_response를 받는 호출 가능한 객체를 씁니다.
# mysite/middleware.py
import time
class TimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
started = time.monotonic()
response = self.get_response(request)
response["X-Elapsed"] = f"{time.monotonic() - started:.3f}"
return response만든 클래스는 MIDDLEWARE에 "mysite.middleware.TimingMiddleware"처럼 경로로 추가합니다.
설정은 django.conf.settings로 어디서든 읽을 수 있습니다. 직접 settings.py 모듈을 가져오지 말고 항상 from django.conf import settings를 씁니다. 그래야 테스트에서 override_settings로 값을 바꾸거나 DJANGO_SETTINGS_MODULE로 다른 설정을 고를 때도 올바른 값을 얻습니다.
path()로 URL을 뷰에 잇고, 이름과 이름공간으로 주소를 거꾸로 만듭니다.INSTALLED_APPS에 등록해야 동작하며, admin.py로 관리자 화면을 얻습니다.django.conf.settings로 읽습니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.