모든 페이지에서 반복되는 공통 부분(헤더, 푸터, 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 사용 O | base.html 사용 X | |
|---|---|---|
| 공통 부분 수정 | 한 파일만 수정 | 파일 100개 전부 수정 |
| 코드 중복 | 없음 | 헤더/푸터/CSS 전부 중복 |
자식 템플릿 여러 개가 동시에 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에 끼워짐
<form action="#" method="GET">
| 속성 | 역할 | 예시에서 |
|---|---|---|
action | 데이터를 어디로 보낼지 | # = 현재 페이지 |
method | 데이터를 어떻게 보낼지 | GET = URL에 붙여서 전송 |
<input type="text" name="query" id="message">
submit을 누르면 name 값이 URL의 key가 된다.
http://127.0.0.1:8000/search?query=hello
↑ ↑
name 입력한 값
name="query" → ?query=helloname="word" 였다면 → ?word=hello1. 사용자가 input에 "hello" 입력
2. submit 버튼 클릭
3. form이 name=값 형태로 URL에 붙임
4. ?query=hello 가 URL 뒤에 추가됨
5. 서버로 GET 요청 전송
| GET | POST | |
|---|---|---|
| 데이터 위치 | URL에 노출 | 숨겨서 전송 |
| 용도 | 검색, 조회 | 로그인, 결제 |
| 예시 | ?query=hello | 비밀번호 전송 |
검색은 URL에 노출돼도 괜찮으니 GET,
비밀번호처럼 민감한 데이터는 URL에 보이면 안 되니 POST!
사용자가 /search/ 접속
↓
urls.py → views.search() 호출
↓
views.py → search.html 렌더링
↓
search.html → base.html의 block content 채움
↓
브라우저에 완성된 HTML 출력
↓
사용자가 검색어 입력 후 submit
↓
GET 요청: /search/?query=hello
사용자가 브라우저에서 URL을 입력하거나 form을 제출하면, 브라우저는 서버에 HTTP 요청(Request) 을 보냄. Django는 이 요청 정보를 HttpRequest 객체 하나에 통째로 담아서 view 함수의 첫 번째 인자로 자동으로 넘겨줌.
def catch(request): # ← Django가 자동으로 넘겨주는 request 객체
...
즉, view 함수를 작성할 때 항상 첫 번째 매개변수로 request를 받는 이유가 바로 이것임. 이름을 꼭 request로 쓸 필요는 없지만, 관례적으로 request라고 씀.
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':
# 데이터 처리하기
request.GETGET 방식으로 전달된 데이터를 담고 있는 딕셔너리 형태의 객체임.
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', '기본값')
request.POSTPOST 방식으로 전달된 데이터를 담고 있는 딕셔너리 형태의 객체임.
GET과 달리 URL에 데이터가 노출되지 않아서 로그인, 회원가입, 민감한 데이터 전송에 사용함.
def login(request):
username = request.POST.get('username')
password = request.POST.get('password')
request.path현재 요청된 URL 경로를 반환함. (도메인 제외)
def my_view(request):
print(request.path) # '/catch/'
request.user현재 요청을 보낸 사용자 정보를 담고 있음.
로그인 여부 확인이나 사용자 정보 접근에 사용함.
def my_view(request):
print(request.user) # 로그인한 사용자 객체
print(request.user.is_authenticated) # 로그인 여부 (True/False)
1. 사용자가 /throw/ 접속
2. 입력창에 "방가방가" 입력 후 제출
3. GET 요청: /catch/?message=방가방가
4. catch view에서 request.GET으로 데이터 꺼냄
5. template에 전달해서 화면에 출력
urlpatterns = [
path('throw/', views.throw),
path('catch/', views.catch),
]
# 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)
{% 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 %}
{% extends 'base.html' %}
{% block content %}
<h1>Catch</h1>
<p>{{ message }}를 받았습니다!</p>
{% endblock content %}
request.GET | request.POST | |
|---|---|---|
| 데이터 위치 | URL 쿼리스트링 | 요청 body (숨겨짐) |
| URL 노출 | O (?message=방가방가) | X |
| 용도 | 검색, 조회, 필터링 | 로그인, 데이터 생성/수정 |
| 북마크 가능 | O | X |
| 데이터 크기 제한 | 있음 | 상대적으로 큼 |

