[Django] 장고에서의 요청 처리
- -
장고에서의 요청 처리
View 함수를 통한 클라이언트 요청 처리 1/3
import json
from django.http import HttpResponse, HttpRequest
def index(request: HttpRequest):
# 단순 text 문자열
content = "HELLO WORLD"
# HTML 문자열
# 복잡한 문자열 조합은 템플릿 엔진을 활용하면 편리하다.
content = """<html><body><h1>HELLO WORLD</h1></body></html>"""
# 개체를 json 문자열로 변환(직렬화, Serialize)
post_list = [
{"title" : "안녕 파이썬", "author" : "Jack"},
{"title" : "안녕 장고", "author" : "Snider"}
]
content = json.dumps(post_list)
# 뷰는 반드시 HttpResponse 인스턴스를 반환해야 한다.
# HtppResponse는 str|bytes 타입의 데이터를 인자로 받아 응답에 사용한다.
return HttpResponse(request)
장고는 뷰 함수를 통해서 클라이언트로부터의 요청을 처리하고 응답을 한다. 뷰에서 문자열 응답은 일반적으로 문자열 응답이다(HTML/JSON 포함).
위의 예제와 같이 단순히 "HELLO WORLD" 문자열 응답을 할 수도 있고, HTML 응답도 할 수 있다. HTML도 사실은 문자열이다. HTML 포맷의 문자열이 있는 것이다. 하지만 해당 예제처럼 사실 저렇게 짧은 HTML 문자열 응답은 거의 없다. 네이버 웹사이트만 해도 페이지 소스에서 확인해 보면 HTML이 최소한 5,000라인이다.
따라서, 5,000라인 정도의 HTML 문자열을 위의 예제처럼 한 땀 한 땀 타이핑을 해서 직접 조합하는 것은 너무도 힘든 작업이고 상상하기도 싫은 일이다. 또한, 코드를 보면 HTML 문자열 색이 전부 파란색(환경에 따라 다를 수 있지만 저렇게 문자열로 감싸면 전부 같은 색이다.)이기 때문에 HTML 포맷에 대한 문법 강조(Syntax Highlight)를 활용할 수 없는 상황이다.
또한, 객체를 json 문자열로 변환하여 응답을 하기도 한다. 클라이언트와 서버가 API 통신을 할 때, 사용되는 문자열 표준 포맷이 있다. 이때, JSON 포맷, XML 포맷은 거의 모든 언어가 지원하기 때문에 API 통신을 할 때, 즉, 클라이언트와 서버 간의 데이터 통신을 할 때에는 서로 객체를 JSON 혹은 XML 포맷의 문자열로 변환해서 전송을 한다. 그럼 받은 측에서는 JSON/XML 문자열을 다시 객체로 변환하여, 프로그램에서 활용하게 된다. 그래서 위의 예제와 같은 방식으로 파이썬 객체를 JSON 문자열로 변환해서 post_list 리스트 객체를 json.dump를 통해 문자열로 변환하고 이를 응답할 수 있다.
View 함수를 통한 클라이언트 요청 처리 2/3
from django.http import HttpResponse, HttpRequest
from django.shortcuts import render
def index(request : HttpRequest):
# 템플릿 엔진을 통해 문자열로 렌더링할 데이터를 준비한다.
# ex) 직접 생성, 데이터베이스에 쿼리, 캐시에서 꺼내기, 파일에서 읽기, 외부에 API 호출
post_list = [
{"title" : "안녕 파이썬", "author" : "Jack"},
{"title" : "안녕 장고", "author" : "Snider"},
]
return render(request, "app/index.html",{
"post_list" : post_list,
})(
이번에는 템플릿 엔진을 활용한 HTML 문자열 조합이다. 첫 번째 예제에서 봤던 한 땀 한 땀 HTML 문자열을 만들기보다, HTML 파일을 별도로 만드는 방법이다. render API가 app/index.html 파일을 활용해서, 복잡한 HTML 문자열을 생성해준다.
템플릿에 대해서는 좀 더 아래에서 살펴볼 예정 이만 지금은 템플릿 엔진을 통해 문자열로 렌더링 할 데이터를 준비한다는 정도로만 인식하고 있으면 될 거 같다.
post_list 리스트는 위의 예제에서는 하드코딩했지만, DB에 쿼리를 통해 만들 수도 있고, 캐시에서 꺼내서 만들 수도 있고, 파일에서 읽어서 만들 수도 있고, 외부 API를 호출해서 그 응답으로 만들 수도 있다. 어떠한 형태로든 상황에 맞게 데이터를 생성하면 된다. 보통은 DB에 쿼리를 이용하여요 데이터를 생성하는 상황이 많다.
View 함수를 통한 클라이언트 요청 처리 3/3
from PTL import Image # Pillow 라이브러리 설치 필요
from django.http import HttpResponse, HttpRequest
def make_image(request : HttpRequest):
# 지정 width/height 크기로 이미지 응답
width = int(request.GET.get("width", 256))
height = int(request.GET.get("height", 256))
width = min(width, 1024)
height = min(height, 1024)
image = Image.new("RGB", (width, height), "red")
response = HttpResponse(content_type = "image/jpg")
image.save(response, "jpeg")
return response
이번에는 이미지를 생성하여 응답하기이다. 이는 PIL(Python Imaging Library)을 활용한다. 원래 PIL은 사라진 라이브러리이며 이를 이어받아 Pillow 라이브러리가 있다.
image = Image.new("RGB", (width, height), "red")
Image.new를 통해 새로운 이미지 객체를 생성할 수 있다. 이미지 모드로 "RGB"를 지정하고, 생성할 이미지 크기를 width, height로 지정한다.
width = int(request.GET.get("width", 256))
height = int(request.GET.get("height", 256))
또한, 기본 색상은 "red"로 이미지에 색상을 채워 넣는다. width와 height를 지정할 때 request.GET에 width가 없으면 256 값을 반환하고, height가 없으면 256을 반환한다. 그 후, 문자열을 정수로 변환하여 width, height 변수에 할당한다.
width = min(width, 1024)
height = min(height, 1024)
최댓값을 제한한다. width, height 값이 1024가 넘으면 최대 1024로 조정하여 width, height에 할당한다.
위의 과정을 통해 이미지를 생성해서 응답으로 돌려준다. 이렇게 동적으로 이미지 또한 생성할 수 있다.
urlpatterns 리스트
View 함수에 대한 라우팅(Routing) 테이블
- 일반적으로 웹서버로 유입되는 클라이언트로부터의 요청을 식별하는 1차 기준은 URL이다.
- settings.ROOT_URLCONF에 지정된 urlpatterns으로부터 하위 urlpatterns들을 가질 수 있다.
# settings.py 파일
ROOT_URLCONF = "프로젝트이름.urls"
장고 설정으로 settings.py 내에 ROOT_URLCONF 설정이 있다. 최상위 URL 설정이라 항상 시작은 저곳에서부터 시작된다.
# 프로젝트/urls.py
# 모든 urls.py에는 urlpatterns 리스트를 기대한다.
urlpatterns = [
path("app/", include("app.urls")),
path("blog/", include("blog.urls")),
]
그래서 위와 같이 app.urls, blog.urls 와 같이 돼있는데 URL이 app으로 시작되는 것이 들어오면 app이라는 이름을 가진 앱에 있는 urls.py 파일을 참고하라는 의미이다. blog도 마찬가지이다.
# app.urls.py
from django.urls import path
from . import views
urlpatterns = [
# / 주소에 매핑
# path 함수의 두번째 인자로 함수 객체를 넘기는 것이 포인트, 함수를 호출하는 것이 아니다.
path("", views.index)
# /dynamic-image/ 주소에 매핑
path("dynamic-image/", views.make_image),
]
app/urls.py 내역을 보면 루트와 마찬가지로 urlpatterns 이름의 리스트를 정의한다. include를 하는 모듈은 항상 urlpatterns가 정의되어있어야 한다.
그래서 include가 기대하는 것은 대상 모듈의 urlpatterns 리스트를 읽어오는 것이다. urlpatterns 이름의 리스트가 없다며, 개발서버 초기화 시에 ImproperlyConfigured 예외가 발생하며 서버가 구동되지 않는다.
urlpatterns 리스트는 path 함수의 리턴값으로 위와 같이 정의해 주면 된다. path의 첫 번째 파라미터로 매칭할 URL 문자열을 지정한다. 빈 문자열 ""은 최상위 주소를 지칭하는 것이다. app/urls.py가 include 시의 path가 "app/"를 지정하였으므로 두 URL 정의가 조합되어 "/app/" 요청 시에 app/views.py 내의 index 함수뷰를 호출하여 요청을 처리한다.
"dynamic-image/" 역시 최상위 주소를 지칭하는 것이다. 이 역시 app/urls.py가 includ시의 path가 "app/"를 지정하였으므로 두 URL 정의가 조합되어 "/app/dynamic-image/" 요청 시에 app/views.py 내의 make_image 함수뷰를 호출하여 요청을 처리한다.
path 함수의 두 번째 파라미터로 함수를 지정한다(일급함수 문법). 함수를 호출하여 그 리턴값을 path 함수의 파라미터로 전달하는 것이 아니다. 함수 그 자체를 파라미터로 전달한다.
'Framework > Django' 카테고리의 다른 글
[Django] 장고 URL 설계 (0) | 2023.12.17 |
---|---|
[Django] 장고 뷰(View) (0) | 2023.12.15 |
[Django] 장고의 설계 철학 (1) | 2023.12.12 |
[Django] 장고 app 생성 (0) | 2023.11.01 |
[Django] VSCode에서 장고 설치하고 프로젝트 만들기 (0) | 2023.09.29 |
소중한 공감 감사합니다