본문 바로가기

문돌이 존버/Django 스터디

장고(Django), 다양한 응답의 함수 기반 뷰(1)

반응형
본 글은 Holix의 "리액트와 함께 장고 시작하기 Complete" 강의를 듣고 작성한 일지입니다.

뷰(View)

기본적인 장고 뷰의 로직은 1개의 HTTP 요청에 대해 1개의 뷰가 호출되는 것입니다. 구체적으로 말하면 urls.py/urlpatterns 리스트에 매핑된 호출 가능한 객체를 가리키는데, 웹 클라이언트로부터의 HTTP 요청을 처리합니다. 뷰에는 크게 2가지 형태가 있으며, 1) 함수 기반 뷰(Function Based View, FBV), 2) 클래스 기반 뷰(Class Based View, CBV)입니다.

FBV는 호출 가능한 객체 그 자체이며 장고 뷰의 기본입니다. CBV는 클래스.as_view() 를 통해 호출 가능한 객체를 생성하거나 리턴합니다.

View 호출 시 인자

- HttpRequest

- URL Caputured Values

첫 번째 인자: HttpRequest 객체
- 현재 요청에 대한 모든 내역을 담고 있음

두 번째 인자: 현재 요청의 URL로부터 Capture된 문자열들
- url/re_path를 통한 처리에선 모든 인자가 string 타입으로 전달
- path를 통한 처리에선 매핑된 Converter의 to_python에 맞게 변환된 값이 인자로 전달
from . import views
from django.urls import path, re_path

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('<int:pk>/', views.post_detail),
    # re_path(r'(?P<pk>\d+/$', views.post_detail) <- 이전 버전
]

위 코드에서 <int:pk> 부분이 Converter이고 pk를 integer로 명시했기 때문에 정수로 변환한 뒤 인자로 전달됩니다.

View 호출에 대한 리턴값

1. HttpResponse 객체를 리턴해야 한다.
- 장고 Middleware에선 뷰에서 HttpResponse 객체를 리턴하기를 기대합니다. 다른 타입을 리턴하면 Middleware에서 처리하는 데 오류가 발생합니다.
(뷰를 미들웨어가 감싸고 있다고 생각하면 됩니다.)
- django.shortcuts.render 함수는 템플릿 응답을 위한 shortcut 함수입니다.

2. 파일과 같은 객체 혹은 str/bytes 타입의 응답을 지원
- str 문자열을 직접 utf8로 인코딩할 필요가 없습니다(장고 디폴트 설정에서 utf8로 인코딩)
- response=HttpResponse()

3. 파일과 같은 객체
response.write(str 또는 bytes 객체)

아래는 위의 내용을 토대로 한 예시 코드입니다.

# views.py
def post_detail(request: HttpRequest, pk: int) -> HttpResponse:
    # request.method
    # request.META
    # request.GET, request.POST, request.FILES, request.body

    content = """
        <html>...</html>
    """
    response = HttpResponse(content)
    response.write(content)
    response['Custom-Header'] = 'Custom Header Value'
    return response

맛보기(?)로 잠깐 CBV를 살펴보면 아래와 같습니다. FBV 기반으로 했을 때와 비교하면 정말 간단하고 매력적으로 보이지만 그 내부가 어떻게 동작하는지 모른다면 이후에 커스터마이징 할 때 더 어려울 수도 있습니다. 

# views.py
from django.views.generic import ListView

# 1번 방법(변할 부분이 없다면 깔끔하고 간단함)
post_list = ListView.as_view(model=Post)

# 2번 방법(Class property, 일단 상속받고 재정의하기 용이함)
class PostListView(ListView):
    model = Post
    
# FBV
# def post_list(request):
#    qs = Post.objects.all()
#    q = request.GET.get('q', '') # q가 없으면 빈 문자열 리턴
#    if q:
#        qs = qs.filter(content__icontains=q)

#    return render(request, 'blog1/post_list.html', {
#        'post_list': qs,
#        'q': q,
#    })
728x90
반응형