Django 기본 - Template 상속, HTML Form, HTTP request 객체

Sally·2026년 4월 16일

Django Template & Form 정리


1. 템플릿 상속 (Template Inheritance)

base.html — 공통 뼈대

모든 페이지에서 반복되는 공통 부분(헤더, 푸터, CSS 등)을 한 곳에 모아두는 파일이다.
{% block content %} 태그로 자식 템플릿이 채울 구멍을 뚫어놓는다.

<!-- articles/base.html -->
<html>
  <head>
    <title>내 사이트</title>
    <link rel="stylesheet" href="style.css">  <!-- 모든 페이지 공통 CSS -->
  </head>
  <body>

    <nav>                                      <!-- 모든 페이지 공통 네비게이션 -->
      <a href="/"></a>
      <a href="/search/">검색</a>
    </nav>

    {% block content %}   <!-- 자식 템플릿이 채울 공간 -->
    {% endblock content %}

    <footer>
      Copyright 2024
    </footer>

  </body>
</html>

자식 템플릿 — 본문 내용

{% extends %} 로 부모를 지정하고, {% block content %} 안에 본문만 작성한다.

<!-- articles/search.html -->
{% extends 'articles/base.html' %}   <!-- base.html을 상속 -->

{% block content %}                  <!-- 구멍을 채우기 시작 -->
  <form action="#" method="GET">
    <label for="message">검색어</label>
    <input type="text" name="query" id="message">
    <input type="submit" value="submit">
  </form>
{% endblock content %}               <!-- 구멍 끝 -->

브라우저에 렌더링된 결과

<html>
  <body>
    <nav>...</nav>

    <!-- block content 자리에 search.html 내용이 들어감 -->
    <form action="#" method="GET">
      <label for="message">검색어</label>
      <input type="text" name="query" id="message">
      <input type="submit" value="submit">
    </form>

    <footer>...</footer>
  </body>
</html>

base.html을 쓰는 이유

base.html 사용 Obase.html 사용 X
공통 부분 수정한 파일만 수정파일 100개 전부 수정
코드 중복없음헤더/푸터/CSS 전부 중복

block content는 순서 충돌이 없다

자식 템플릿 여러 개가 동시에 base.html에 들어가는 게 아니다.
URL 요청이 들어오면 views.py딱 하나의 자식 템플릿만 골라서 렌더링한다.

# views.py
def search(request):
    return render(request, 'articles/search.html')  # 얘만 렌더링

def index(request):
    return render(request, 'articles/index.html')   # 얘만 렌더링

def dinner(request):
    return render(request, 'articles/dinner.html')  # 얘만 렌더링
/search/ 요청  →  search.html이 block을 채움
/articles/ 요청  →  index.html이 block을 채움
/dinner/ 요청  →  dinner.html이 block을 채움

URL 요청 → views.py가 html 결정 → 그 html 하나만 base에 끼워짐


2. HTML Form

form의 핵심 속성

<form action="#" method="GET">
속성역할예시에서
action데이터를 어디로 보낼지# = 현재 페이지
method데이터를 어떻게 보낼지GET = URL에 붙여서 전송

name 속성이 핵심

<input type="text" name="query" id="message">

submit을 누르면 name 값이 URL의 key가 된다.

http://127.0.0.1:8000/search?query=hello
                              ↑      ↑
                             name   입력한 값
  • name="query"?query=hello
  • name="word" 였다면 → ?word=hello

form 전체 흐름

1. 사용자가 input에 "hello" 입력
2. submit 버튼 클릭
3. form이 name=값 형태로 URL에 붙임
4. ?query=hello 가 URL 뒤에 추가됨
5. 서버로 GET 요청 전송

GET vs POST

GETPOST
데이터 위치URL에 노출숨겨서 전송
용도검색, 조회로그인, 결제
예시?query=hello비밀번호 전송

검색은 URL에 노출돼도 괜찮으니 GET,
비밀번호처럼 민감한 데이터는 URL에 보이면 안 되니 POST!


3. 전체 흐름 요약

사용자가 /search/ 접속
    ↓
urls.py → views.search() 호출
    ↓
views.py → search.html 렌더링
    ↓
search.html → base.html의 block content 채움
    ↓
브라우저에 완성된 HTML 출력
    ↓
사용자가 검색어 입력 후 submit
    ↓
GET 요청: /search/?query=hello

Django HTTP request 객체

Request 객체란?

사용자가 브라우저에서 URL을 입력하거나 form을 제출하면, 브라우저는 서버에 HTTP 요청(Request) 을 보냄. Django는 이 요청 정보를 HttpRequest 객체 하나에 통째로 담아서 view 함수의 첫 번째 인자로 자동으로 넘겨줌.

def catch(request):   # ← Django가 자동으로 넘겨주는 request 객체
    ...

즉, view 함수를 작성할 때 항상 첫 번째 매개변수로 request를 받는 이유가 바로 이것임. 이름을 꼭 request로 쓸 필요는 없지만, 관례적으로 request라고 씀.


request 객체의 주요 속성

1. request.method

현재 요청이 어떤 방식으로 왔는지 문자열로 반환함.

def my_view(request):
    print(request.method)  # 'GET' 또는 'POST'
상황
'GET'URL 직접 접속, 검색, 링크 클릭
'POST'form 제출 (로그인, 데이터 생성 등)

조건문과 함께 자주 사용함.

def my_view(request):
    if request.method == 'GET':
        # 페이지 보여주기
    elif request.method == 'POST':
        # 데이터 처리하기

2. request.GET

GET 방식으로 전달된 데이터를 담고 있는 딕셔너리 형태의 객체임.
URL의 ? 뒤에 붙는 쿼리스트링(Query String) 데이터를 여기서 꺼낼 수 있음.

http://127.0.0.1:8000/catch/?message=방가방가
                              ↑ 이 부분이 쿼리스트링
def catch(request):
    message = request.GET.get('message')
    # message = '방가방가'

request.GET은 Python의 일반 딕셔너리와 거의 동일하게 동작함.
다만 .get('key') 방식을 권장하는데, 키가 없을 때 에러 대신 None을 반환하기 때문임.

# 키가 없을 때 기본값 지정도 가능
message = request.GET.get('message', '기본값')

3. request.POST

POST 방식으로 전달된 데이터를 담고 있는 딕셔너리 형태의 객체임.
GET과 달리 URL에 데이터가 노출되지 않아서 로그인, 회원가입, 민감한 데이터 전송에 사용함.

def login(request):
    username = request.POST.get('username')
    password = request.POST.get('password')

4. request.path

현재 요청된 URL 경로를 반환함. (도메인 제외)

def my_view(request):
    print(request.path)  # '/catch/'

5. request.user

현재 요청을 보낸 사용자 정보를 담고 있음.
로그인 여부 확인이나 사용자 정보 접근에 사용함.

def my_view(request):
    print(request.user)           # 로그인한 사용자 객체
    print(request.user.is_authenticated)  # 로그인 여부 (True/False)

Throw & Catch 실습으로 이해하기

전체 흐름

1. 사용자가 /throw/ 접속
2. 입력창에 "방가방가" 입력 후 제출
3. GET 요청: /catch/?message=방가방가
4. catch view에서 request.GET으로 데이터 꺼냄
5. template에 전달해서 화면에 출력

urls.py

urlpatterns = [
    path('throw/', views.throw),
    path('catch/', views.catch),
]

views.py

# throw: 입력 폼을 보여주는 view
def throw(request):
    return render(request, 'throw.html')

# catch: 데이터를 받아서 출력하는 view
def catch(request):
    message = request.GET.get('message')  # request 객체에서 데이터 꺼냄
    context = {
        'message': message,
    }
    return render(request, 'catch.html', context)

throw.html

{% extends 'base.html' %}

{% block content %}
  <h1>Throw</h1>
  <form action="/catch/" method="GET">
    <input type="text" name="message">
    <input type="submit" value="제출">
  </form>
{% endblock content %}

catch.html

{% extends 'base.html' %}

{% block content %}
  <h1>Catch</h1>
  <p>{{ message }}를 받았습니다!</p>
{% endblock content %}

request.GET vs request.POST 비교

request.GETrequest.POST
데이터 위치URL 쿼리스트링요청 body (숨겨짐)
URL 노출O (?message=방가방가)X
용도검색, 조회, 필터링로그인, 데이터 생성/수정
북마크 가능OX
데이터 크기 제한있음상대적으로 큼


profile
sally

0개의 댓글