Django 6.0 완전 가이드 2026: 복합 기본 키, 백그라운드 태스크, 기술 면접 질문

Django 6.0의 핵심 기능을 분석합니다. CompositePrimaryKey를 활용한 복합 기본 키, 내장 백그라운드 태스크, 템플릿 파셜, CSP 미들웨어 설정법과 2026년 기술 면접 대비 질문을 코드 예제와 함께 다룹니다.

Django 6.0 복합 기본 키와 백그라운드 태스크 튜토리얼

Django 6.0은 2026년 Python 웹 프레임워크 생태계에서 중대한 전환점을 나타냅니다. 이번 메이저 릴리스는 커뮤니티가 오랜 기간 요청해온 기능들을 프레임워크 코어에 직접 통합합니다. ORM에서의 복합 기본 키 네이티브 지원, 외부 브로커 없이 동작하는 내장 백그라운드 태스크 시스템, 템플릿 파셜을 통한 재사용 가능한 UI 컴포넌트, 그리고 Content Security Policy 미들웨어가 핵심 변경 사항입니다. 각 기능은 서드파티 패키지에 대한 의존도를 줄이고 프로덕션 Django 애플리케이션의 아키텍처를 단순화하는 방향으로 설계되었습니다.

2026년 Django 버전 타임라인

Django는 약 8개월 주기로 메이저 버전을 릴리스합니다. Django 5.2 LTS(2025년 4월)에서 복합 기본 키가 안정 기능으로 최초 도입되었습니다. Django 6.0(2025년 12월)은 이를 ORM 전반에 완전히 통합하면서 백그라운드 태스크 시스템, 템플릿 파셜, CSP 미들웨어를 추가했습니다. Django 6.1은 2026년 8월 출시가 예정되어 있으며, Python 3.12 이상이 필수 요구 사항입니다.

CompositePrimaryKey를 활용한 복합 기본 키

관계형 데이터베이스에서 복합 기본 키는 두 개 이상의 컬럼 조합으로 레코드를 고유하게 식별하는 방식입니다. Django 5.2 이전까지 이러한 관계를 모델링하려면 unique_together 제약 조건이나 서드파티 패키지를 사용하는 우회 방법이 필요했습니다. CompositePrimaryKey는 이 문제를 ORM 레벨에서 근본적으로 해결합니다.

가장 대표적인 사용 사례는 두 개의 외래 키 조합이 레코드의 고유 식별자를 구성하는 중간 테이블입니다. 다음 예제는 각 제품이 각 창고에서 보유하는 수량을 나타내는 재고 모델을 정의합니다.

python
# models.py
from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    sku = models.CharField(max_length=20, unique=True)

class Warehouse(models.Model):
    code = models.CharField(max_length=10, primary_key=True)
    location = models.CharField(max_length=200)

class Inventory(models.Model):
    pk = models.CompositePrimaryKey("product_id", "warehouse_id")
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=0)
    last_restocked = models.DateTimeField(auto_now=True)

pk 필드는 모델 필드 이름이 아닌 데이터베이스의 실제 컬럼 이름을 인자로 받습니다. Django는 데이터베이스 레벨에서 PRIMARY KEY (product_id, warehouse_id) 제약 조건을 생성하며, 자동 증가 id 필드 없이도 레코드의 유일성을 보장합니다. 이 접근 방식은 관계형 데이터베이스의 표준 모델링 원칙에 부합합니다.

ORM에서 복합 키 조회하기

복합 기본 키를 사용하는 모델과의 상호작용은 기존 Django ORM 인터페이스를 그대로 유지합니다. 복합 키는 Python 튜플로 표현되며, 레코드의 생성, 필터링, 할당이 직관적으로 수행됩니다.

python
# views.py
from .models import Inventory, Product, Warehouse

# Create records
laptop = Product.objects.create(name="Laptop Pro", sku="LP-001")
warehouse_a = Warehouse.objects.create(code="WH-A", location="Berlin")

item = Inventory.objects.create(
    product=laptop,
    warehouse=warehouse_a,
    quantity=50
)

# Access the composite pk as a tuple
print(item.pk)  # (1, "WH-A")

# Filter by composite pk
result = Inventory.objects.filter(pk=(1, "WH-A")).first()

# Assign a composite pk directly
new_item = Inventory(pk=(2, "WH-B"))
print(new_item.product_id)  # 2
print(new_item.warehouse_id)  # "WH-B"

이 기능은 기존 데이터베이스 스키마를 다루거나 복합 키를 이미 지원하는 다른 ORM에서 마이그레이션하는 팀에게 특히 유용합니다. Django Admin, Django REST Framework의 시리얼라이저, 그리고 마이그레이션 시스템 모두 CompositePrimaryKey를 사용하는 모델을 자동으로 인식합니다. 기존의 unique_together 방식과 달리 불필요한 대리 키(surrogate key) 없이 데이터베이스의 의미론적 무결성을 유지할 수 있습니다.

@task 데코레이터를 활용한 내장 백그라운드 태스크

Django 6.0은 프레임워크 내부에 백그라운드 태스크 시스템을 직접 통합합니다. django.tasks 모듈은 @task 데코레이터와 .enqueue() 메서드를 제공하여, 외부 메시지 브로커나 별도의 워커 프로세스를 구성하지 않고도 함수 실행을 비동기로 지연시킬 수 있습니다.

이 시스템은 HTTP 요청-응답 사이클을 차단해서는 안 되는 일반적인 작업을 대상으로 합니다. 이메일 발송, 리포트 생성, 파일 처리, 외부 API 호출 등이 대표적입니다. 태스크 정의는 Django의 기존 관례에 따라 각 앱의 tasks.py 모듈에서 수행합니다.

python
# tasks.py
from django.tasks import task
from django.core.mail import send_mail

@task
def send_welcome_email(user_email, username):
    """Send a welcome email after user registration."""
    send_mail(
        subject="Welcome to the platform",
        message=f"Hello {username}, your account is ready.",
        from_email=None,  # uses DEFAULT_FROM_EMAIL
        recipient_list=[user_email],
    )
    return f"Email sent to {user_email}"

@task
def generate_report(report_id, format="pdf"):
    """Generate an export report asynchronously."""
    from .services import ReportService
    report = ReportService.generate(report_id, format=format)
    return report.file_path

뷰에서 태스크를 디스패치할 때는 .enqueue() 메서드를 사용합니다. 이 메서드는 인자를 직렬화하여 설정된 백엔드로 전달하고, 태스크가 비동기적으로 실행되도록 예약합니다.

python
# views.py
from .tasks import send_welcome_email, generate_report

def register_user(request):
    # ... user creation logic ...
    # Enqueue the task for background execution
    send_welcome_email.enqueue(
        user_email=user.email,
        username=user.username
    )
    return redirect("dashboard")

def export_view(request, report_id):
    generate_report.enqueue(report_id=report_id, format="csv")
    return JsonResponse({"status": "processing"})

Django 6.0은 데이터베이스 기반의 기본 백엔드와 함께 더 높은 처리량이 필요한 시나리오를 위한 Redis 백엔드를 제공합니다. settings.py에서 백엔드 선택, 워커 수, 폴링 간격 등의 파라미터를 조정할 수 있습니다.

내장 백그라운드 태스크 vs Celery

Django 6.0의 네이티브 태스크 시스템은 단순하거나 중간 수준의 비동기 작업을 효율적으로 처리합니다. 그러나 고급 큐 라우팅, 복잡한 워크플로우(chain, chord, group), 지수 백오프를 포함한 세밀한 재시도 정책, 또는 여러 서버에 걸친 분산 처리가 필요한 경우에는 Celery가 여전히 적합한 도구입니다. 내장 태스크는 fire-and-forget 패턴에 최적화되어 있고, Celery는 엔터프라이즈 수준의 태스크 오케스트레이션에 적합합니다.

템플릿 파셜: 재사용 가능한 UI 프래그먼트

Django의 템플릿 엔진에 프론트엔드 프레임워크에서는 이미 기본 기능으로 자리잡은 기능이 추가됩니다. 하나의 파일 내에서 재사용 가능한 프래그먼트를 정의하고 선택적으로 참조할 수 있는 기능입니다. {% partialdef %} 태그와 {% partial %} 태그를 사용하면 여러 UI 컴포넌트를 단일 템플릿 파일에 묶어두고 필요한 프래그먼트만 선택적으로 사용할 수 있습니다.

다음 예제는 하나의 제품에 대해 카탈로그 뷰용 카드와 재고 테이블용 행이라는 두 가지 시각적 표현을 동일한 템플릿 파일에 정의합니다.

html
<!-- templates/components/cards.html -->
{% partialdef product_card %}
<div class="card">
    <h3>{{ product.name }}</h3>
    <p class="price">{{ product.price|floatformat:2 }} EUR</p>
    <span class="stock {% if product.in_stock %}available{% else %}sold-out{% endif %}">
        {% if product.in_stock %}In Stock{% else %}Sold Out{% endif %}
    </span>
</div>
{% endpartialdef %}

{% partialdef product_row %}
<tr>
    <td>{{ product.name }}</td>
    <td>{{ product.price|floatformat:2 }} EUR</td>
    <td>{{ product.quantity }}</td>
</tr>
{% endpartialdef %}

특정 파셜만 선택적으로 포함할 때는 {% include %} 태그에서 #이름 프래그먼트 구문을 사용합니다.

html
<!-- templates/shop/catalog.html -->
{% extends "base.html" %}

{% block content %}
<div class="product-grid">
    {% for product in products %}
        {% include "components/cards.html#product_card" %}
    {% endfor %}
</div>
{% endblock %}

템플릿 파셜의 핵심 장점은 파일 증식(file proliferation)의 감소에 있습니다. 이전에는 컴포넌트의 각 시각적 변형마다 별도의 파일이 필요했습니다. 이제 관련된 변형들이 하나의 파일에 공존하여 코드의 유지보수성과 탐색 효율이 향상됩니다. 이 기능은 HTMX와 같은 부분 HTML 교환 패턴과도 자연스럽게 통합됩니다. 서버가 전체 템플릿을 렌더링하지 않고 페이지의 특정 프래그먼트만 반환해야 하는 상황에서 특히 유용합니다.

Django 면접 준비가 되셨나요?

인터랙티브 시뮬레이터, flashcards, 기술 테스트로 연습하세요.

네이티브 Content Security Policy 미들웨어

크로스 사이트 스크립팅(XSS)과 콘텐츠 인젝션 공격에 대한 방어는 올바르게 구성된 Content Security Policy 헤더를 필요로 합니다. Django 6.0은 전용 미들웨어와 django.utils.csp 모듈을 내장하여 django-csp와 같은 외부 패키지의 필요성을 제거합니다.

설정은 settings.py에서 CSP 디렉티브와 허용 값을 매핑하는 딕셔너리를 통해 정의합니다.

python
# settings.py
from django.utils.csp import CSP

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.middleware.security.ContentSecurityPolicyMiddleware",
    # ... other middleware
]

SECURE_CSP = {
    "default-src": [CSP.SELF],
    "script-src": [CSP.SELF, CSP.NONCE],
    "style-src": [CSP.SELF, "https://fonts.googleapis.com"],
    "img-src": [CSP.SELF, "https:", "data:"],
    "font-src": [CSP.SELF, "https://fonts.gstatic.com"],
    "connect-src": [CSP.SELF],
}

# Report-only mode for testing (does not block, only reports violations)
SECURE_CSP_REPORT_ONLY = {
    "default-src": [CSP.SELF],
    "report-uri": ["/csp-report/"],
}

CSP.NONCE 상수는 각 요청마다 고유한 nonce 값을 자동으로 생성하고 템플릿의 <script> 태그에 주입합니다. 이를 통해 정당한 인라인 스크립트는 실행을 허용하면서 공격자가 주입한 스크립트는 차단할 수 있습니다. SECURE_CSP_REPORT_ONLY 모드는 배포 단계에서 특히 유용합니다. 리소스를 실제로 차단하지 않으면서 위반 사항만 기록하므로, 차단 모드를 활성화하기 전에 정책을 점진적으로 다듬을 수 있습니다.

네이티브 통합은 Django 템플릿 엔진과의 완전한 호환성을 보장합니다. {% static %} 블록과 관리자 패널의 인라인 스크립트에 nonce 속성이 자동으로 생성됩니다.

Django 6.0의 기타 주요 변경 사항

주요 기능 외에도 Django 6.0은 일상적인 개발 경험에 영향을 미치는 여러 개선 사항을 포함합니다.

BigAutoField 기본 적용: 새로운 프로젝트에서 DEFAULT_AUTO_FIELDBigAutoField를 가리킵니다. 기존의 AutoField가 가진 약 21억 개 레코드 제한이 사라집니다. 이 값을 명시적으로 설정하지 않은 기존 프로젝트에서는 마이그레이션 시 경고가 표시됩니다.

비동기 페이지네이션: 페이지네이션된 QuerySet이 await page.ahas_next()await page.ahas_previous()와 같은 비동기 메서드를 지원합니다. 비동기 뷰에서 이벤트 루프를 차단하지 않고 결과를 페이지네이션할 수 있어 ASGI 애플리케이션의 처리량이 향상됩니다.

셸 자동 임포트: python manage.py shell 명령이 프로젝트의 모든 모델과 자주 사용되는 모듈(django.db.models, django.utils.timezone, datetime)을 자동으로 임포트합니다. 디버깅 세션을 시작할 때마다 반복적으로 임포트 구문을 입력하는 번거로움이 사라집니다.

메일 API 현대화: django.core.mail 모듈이 인라인 첨부 파일, 커스텀 헤더, 플루언트 인터페이스를 네이티브로 지원합니다. MIME 객체를 직접 조작하지 않고도 복잡한 이메일을 작성할 수 있습니다.

Django 5.2에서 6.0으로의 마이그레이션

Django 6.0은 Python 3.12 이상을 필수로 요구합니다. DEFAULT_AUTO_FIELD를 명시적으로 설정하지 않은 프로젝트에서는 마이그레이션 시 경고가 발생할 수 있으므로, 업그레이드 전에 settings.py에서 이 값을 확인해야 합니다. 또한 django-csp와 같은 서드파티 CSP 패키지를 사용 중이라면, 내장 미들웨어로의 전환 시 설정 키 이름이 달라질 수 있으므로 공식 마이그레이션 가이드를 참조하는 것이 권장됩니다. 테스트 스위트를 먼저 실행하여 비호환성 여부를 사전에 확인하는 것이 안전합니다.

2026년 Django 기술 면접 질문

2026년 Python 백엔드 포지션의 기술 면접에서는 Django 6.0의 신규 기능에 대한 이해도를 평가하는 질문이 점차 포함되고 있습니다. 다음은 Django 면접 과정에서 출제 가능성이 높은 주제들입니다.

Q: unique_togetherCompositePrimaryKey의 차이점은 무엇입니까?

unique_together는 컬럼 집합에 대한 유니크 제약 조건을 생성하지만, 모델은 자동 증가 id 필드를 기본 키로 유지합니다. 반면 CompositePrimaryKeyid 필드를 제거하고 지정된 컬럼 조합을 데이터베이스 레벨의 실제 기본 키로 설정합니다. 전자는 추가적인 제약 조건이고, 후자는 레코드의 정체성 자체를 재정의합니다.

Q: Django 6.0의 네이티브 태스크와 Celery 중 어떤 상황에서 각각을 선택해야 합니까?

네이티브 태스크 시스템은 큐 라우팅, 정교한 재시도 메커니즘, Canvas 워크플로우(chain, group, chord)가 필요하지 않은 단순한 백그라운드 작업에 적합합니다. Celery는 여러 서버에 걸친 분산 처리, Celery Beat를 활용한 고급 주기적 스케줄링, Flower와 같은 도구를 통한 실시간 모니터링이 필요한 애플리케이션에서 선택해야 합니다.

Q: ORM에서 복합 기본 키는 어떻게 접근합니까?

CompositePrimaryKey를 사용하는 인스턴스의 pk 속성은 키를 구성하는 컬럼 값들의 Python 튜플을 반환합니다. 필터링은 Model.objects.filter(pk=(value1, value2))로, 할당은 instance = Model(pk=(value1, value2))로 수행합니다. ORM이 튜플을 자동으로 해당 필드에 분해(unpack)하여 매핑합니다.

Q: 템플릿 파셜이 기존의 다중 include 파일 방식 대비 어떤 이점을 제공합니까?

템플릿 파셜은 여러 재사용 가능한 프래그먼트를 하나의 파일에 정의할 수 있어, 작은 파일들의 증식을 줄이고 코드 탐색을 용이하게 합니다. {% include "file.html#name" %} 구문으로 특정 프래그먼트만 선택적으로 참조할 수 있으며, HTMX와 같은 부분 HTML 교환 패턴과의 통합에서도 효율적입니다.

Q: CSP nonce 기반 스크립트 보호의 동작 원리를 설명해 주십시오.

CSP.NONCEscript-src 디렉티브에 포함하면, Django가 각 HTTP 요청마다 고유한 암호학적 nonce를 생성합니다. 이 nonce는 템플릿의 <script> 태그에 nonce 속성으로 자동 삽입됩니다. 브라우저는 응답 헤더의 CSP nonce와 일치하는 스크립트만 실행을 허용하므로, 공격자가 페이지에 주입한 스크립트는 nonce가 없어 차단됩니다.

결론

  • 복합 기본 키는 중간 테이블과 관계 테이블에서 인위적인 id 필드의 필요성을 제거하여, Django ORM을 관계형 데이터베이스의 표준 모델링 원칙에 부합시킵니다
  • 내장 백그라운드 태스크는 외부 브로커와 워커에 대한 의존성을 제거하여, 단순한 비동기 작업의 운영 복잡성을 크게 줄입니다
  • 템플릿 파셜은 재사용 가능한 프래그먼트를 단일 파일 내에 구성하여 템플릿 파일의 증식을 억제하고, HTMX와 같은 부분 HTML 교환 패턴과의 통합을 촉진합니다
  • 네이티브 CSP 미들웨어는 nonce 자동 생성과 report-only 모드를 통해 XSS 공격에 대한 방어를 점진적으로 배포할 수 있는 체계적인 방법을 제공합니다
  • BigAutoField 기본 적용은 대용량 테이블에서 기본 키 고갈 문제를 추가 설정 없이 사전에 방지합니다
  • 비동기 페이지네이션셸 자동 임포트는 프로덕션 코드와 디버깅 세션 모두에서 개발 생산성을 향상시킵니다
  • Django 6.0은 Python 3.12 이상을 필수로 요구하며, PostgreSQL, MySQL, SQLite, Oracle 등 주요 데이터베이스와의 호환성을 유지합니다

연습을 시작하세요!

면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.

태그

#django
#python
#composite-primary-keys
#background-tasks
#csp

공유

관련 기사