본문 바로가기

문돌이 존버/Django 스터디

장고(Django), 클래스 기반 뷰 시작 및 Base Views 이해하기

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

Class Based View

CBV는 View 함수를 만들어주는 클래스를 의미합니다. as_view() 클래스 함수를 통해 View 함수를 생성하고, 상속을 통해 여러 기능들을 믹스인합니다.

그 전에 앞서 post_detail 뷰 함수를 구현하는데, pk를 전달할 때 해당하는 id가 없으면 DoesNotExist 예외 처리가 발생합니다. 이때 try, except 구문을 사용할 수도 있지만 그보다 더 편리한 것은 get_object_or_404 를 사용하는 것입니다.

# views.py
from django.http.response import Http404, HttpResponse, Http404
def post_detail(request: HttpRequest, pk: int) -> HttpResponse:
    try:
        post = Post.objects.get(pk=pk)
    except Post.DoesNotExist:
        raise Http404
# views.py
from django.shortcuts import get_object_or_404, render
def post_detail(request: HttpRequest, pk: int) -> HttpResponse:
    post = get_object_or_404(Post, pk=pk)

장고에서 기본으로 제공하는 CBV를 활용하는 예시는 아래와 같습니다.

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

# pk_url_kwarg를 'pk'로 지정했으면 따로 명시해주지 않아도 됨
post_detail = DetailView.as_view(model=Post, pk_url_kwarg='id')
article_detail = DetailView.as_view(model=Article, pk_url_kwarg='id')

# 상속을 통한 CBV 속성 정의
from django.views.generic import DetailView

class PostDetailView(DetailView):
    model = Post
    pk_url_kwarg = 'id'

post_detail = PostDetailView.as_view()

위 코드 주석에서 언급한 pk_url_kwarg urls.py 에서 path에 넘겨주는 쿼리 파라미터를 가리킵니다.

# urls.py
urlpatterns = [
    path('post/<int:id>/', post_detail), # 'pk'라면 위 코드에서 pk_url_kwarg 파라미터 불필요
    path('article/<int:id>/', article_detail),
]

장고의 CBV는 강력한 기능이 될 수 있지만, FBV(함수 기반 뷰)에 대한 이해 없이 사용한다면 위험해질 수 있다고 합니다. 항상 공식문서 및 소스코드를 살펴보는 연습이 필요할 것 같습니다.

https://github.com/django/django/tree/main/django/views/generic

Base Views

View는 모든 CBV의 모체이지만 해당 CBV를 직접 쓸 일은 거의 없습니다. http method별로 지정 이름의 멤버함수를 호출토록 구현해 놓았는데, 예를 들어 GET 요청이 들어오면 소문자 get 함수를 호출하는 것입니다.

일단 TemplateView 를 한 번 시도해보겠습니다.

깃허브에 있는 소스코드를 보는 것도 좋지만 속성과 메서드가 잘 정리된 사이트도 첨부합니다.
https://ccbv.co.uk/projects/Django/3.1/django.views.generic.base/TemplateView/
# 프로젝트/urls.py
from django.views.generic import TemplateView

urlpatterns = [
    path('', TemplateView.as_view(template_name='root.html'), name='root'),
    ...,
]
# settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            # File System Template Loader <- 특정 앱에 속하지 않은 탬플릿용
            os.path.join(BASE_DIR, 'instagram', 'templates'),
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                ...
            ],
        },
    },
]

위와 같이 설정하면 instagram이란 폴더 내부에 templates란 폴더를 생성하시면 됩니다. 물론 상위 폴더를 정하지 않아도 되며 그럴 경우 templates란 폴더는 프로젝트 디렉토리에 생성하시면 됩니다. 그러면 루트 url에 접속하더라도 root.html 을 작성해줬기 때문에 해당 html 내용을 화면에 보여줄 것입니다.

다음은 RedirectView를 살펴보겠습니다.

https://ccbv.co.uk/projects/Django/3.1/django.views.generic.base/RedirectView/
# 프로젝트/urls.py
from django.views.generic import TemplateView, RedirectView

urlpatterns = [
    path('', RedirectView.as_view(url='/blog1/'), name='root'),
    ...,
]

말 그대로 특정 url에 접속했을 때 해당 url이 없어졌거나 임시로 멈춘 경우 다른 url로 이동하게끔 만들어주는 것입니다. 영구적 이동 대신 임시로 이동하는 것을 하고(permanent=False <- 디폴트), 이동할 url은 blog1으로 지정했습니다.

이렇게 하면 "127.0.0.1:8000/"에 접속해도 바로 "127.0.0.1:8000/blog1/" 주소의 페이지로 이동하게 됩니다. 직접 url을 명시하지 않고 URL Reverse를 통한 방법도 있습니다. 이를 위해선 지난 시간에 설명드렸듯이 앱의 urls.py 에서 app_name 변수를 지정해야 합니다.

# 앱/urls.py
app_name = 'blog1'
# 프로젝트/urls.py
from django.views.generic import TemplateView, RedirectView

urlpatterns = [
    path('', RedirectView.as_view(pattern_name='blog1:post_list'), name='root'),
    ...,
]

참고로 장고에서는 url을 직접 명시하는 것보단 pattern_name을 선호한다고 합니다.

728x90
반응형