FBV (Function Based View)와 CBV (Class Based View)

210724

FBV (Function Based View)로 블로그 리스트 페이지 만들기

기본적으로 프로젝트 폴더에 있는 urls.py 에는 admin/ 만 등록되어 있다. 따라서 다음과 같이 127.0.0.1/blog 주소로 들어가면 404 오류가 난다.

urls.py 에 있는 urlpatterns 은 이정표의 의미. 나아갈 수 있는 링크들을 의미한다. 여기에 blog/ 를 추가해주면 된다.

urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('blog/', include('blog.urls')),
    path('admin/', admin.site.urls),
]
  • 이 때 include 라는 함수를 import 해줘야 한다

  • blog 앱 폴더에는 아직 urls 라는 파일이 없다. 따라서 이를 추가해줘야 한다.

blog/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),
]
  • 이 때 views.index 를 호출하므로 views.py 에서 index 함수를 선언해줘야 한다.

  • 지금처럼 하는 방법이 FBV 방법

blog/views.py

from django.shortcuts import render

def index(request):
    return render(
        request, 
        'blog/index.html',
    )
  • blog의 index.html을 가지고 렌더링 하라는 뜻

  • 따라서 index.html이 또 필요하다.

    • templates 라는 폴더 안에, blog 라는 폴더 안에 index.html을 만든다

    • templates/blog/index.html

    • 앱의 독립성을 위해 이렇게 작업하며 추후에 추가 설명

blog/templates/blog/index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    <h1>blog</h1>
</body>
</html>

https://m.blog.naver.com/nuberus/221747636515
  • 지금까지 한 작업은 클라이언트에서 View로 요청을하고 View가 템플릿을 렌더링 한 후 응답을 준 과정이다.

  • 이제 Model에서 DB로 쿼리를 날린 후 데이터를 얻어서 응답을 주는 과정을 해보려고 한다.

blog/views.py

from django.shortcuts import render
from .models import Post

def index(request):
    posts = Post.objects.all()
    return render(
        request,
        'blog/index.html',
        {
            'posts' : posts,
        },
    )
  • 렌더링의 리턴값으로 posts 라는 dictionary를 추가했다.

    • 이 posts는 models.py에 있는 post class이다.

지금부터의 파일들은 특별한 명시가 없으면 모두 blog 앱 내부에 있는 파일이다.

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    <h1>blog</h1>

    {% for p in posts %}
        <h3>{{ p }}</h3>
    {% endfor %}
</body>
</html>
  • 10-12

    • html에서 동적언어를 쓸 수 있게끔 장고에서 지원한다.

    • for문을 시작할 때와 끝날 때 {% %} 를 써준다.

    • posts는 views.py에 있는 dictionary 값으로 'posts' key에 대한 value 값들을 하나씩 <h3> 형태로 작성되게 한다.

  • 이 때 어떻게 p 를 부르기만 해도 db에 저장된 내용이 다 뜰까?

    • 이유는 models.py에 정의되어있는 __str__ 함수 때문

models.py

    def __str__(self):
        return f"{self.pk} {self.title}"

좀 더 추가해보자.

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    <h1>blog</h1>

    {% for p in posts %}
        <hr/>
        <h3>{{ p }}</h3>
        <h4>{{ p.create_at }}</h4>
        <p> {{ p.context }}</p>
    {% endfor %}
</body>
</html>

또한, posts의 값들을 특정 테이블값으로 정렬할 수 있다.

views.py

# pk 순
posts = Post.objects.all().order_by('pk')

# pk 역순
posts = Post.objects.all().order_by('-pk')
  • 여기서 objects.all()은 쿼리문이라고 생각하면 된다.

FBV (Function Based View)로 블로그 상세 페이지 만들기

blog 페이지에서 게시글을 눌렀을 때 새로운 페이지로 이동하는 과정을 구성할 것임

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('<int:pk>/', views.single_post_page)
    path('', views.index),
]
  • <> 안에는 자료형을 넣을 수 있으며 pk가 정수로 오기 때문에 다음과 같이 가능

  • views.pysingle_post_page 함수를 추가할 것임

views.py

def single_post_page(request, pk):
    post = Post.objects.get(pk=pk)
    return render(
        request,
        'blog/single_page.html',
        {
            'post': post,
        }
    )

single_page.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>{{ post.title }} - Blog</title>
</head>
<body>
    <nav>
        <a href="/blog/">Blog</a>
    </nav>

    <h1>{{ post.title }}</h1>
    <h4>{{ post.created_at }}</h4>
    <p>{{ post.content }}</p>
    <p>여기에 댓글이 들어올 수 있겠죠?</p>
</body>
</html>

여기서 블로그를 누르면 모든 /blog 로 이동한다.

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    <h1>blog</h1>

    {% for p in posts %}
        <hr/>
        <h3>><a href="{{ p.get_absolute_url }}">{{ p }}</a></h3>
        <h4>{{ p.create_at }}</h4>
        <p> {{ p.context }}</p>
    {% endfor %}
</body>
</html>
  • 여기서 p.get_absolute_url 를 호출할 수 있다. 이것은 model.py 에서 정의해줘야 하는 함수이지만 장고에서 제공해주는 기능이다.

    • 장고에서 제공하는 기능을 정의해주면 된다는 뜻

models.py

    def get_absolute_url(self):
        return f'/blog/{self.pk}'

각 포스트에서 /blog로 이동할 수 있으며 admin 페이지에서도 view on site 기능이 추가되었다.

FBV로 대문 페이지 자기소개페이지 만들기

127.0.0.1/8000 에서 blog나 admin을 입력하지 않으면 에러가 발생한다. 대문 페이지도 마련해주자.

urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('blog/', include('blog.urls')),
    path('admin/', admin.site.urls),
    path('', include('single_pages.urls'))
]

single_pages/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.landing),
]

single_pages/views.py

from django.shortcuts import render

def landing(request):
    return render(
        request,
        'single_pages/landing.html',
    )

single_pages/templates/single_pages/landing.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>상민이의 웹사이트</title>
</head>
<body>
    <nav>
        <a href="/blog/">Blog</a>
        <a href="/about_me/">About me</a>
    </nav>

    <h1>안녕하세요. 전상민입니다.</h1>
    <h2>대문 페이지</h2>
    <h3>개발중...</h3>
</body>
</html>

CBV로 블로그 포스트 목록 페이지 만들기

장고에서 이러한 블로그 페이지들을 클래스로 제공하고 있다.

blog/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('<int:pk>/', views.single_post_page),
    path('', views.PostList.as_view())
    # path('', views.index),
]

blog/views.py

from django.shortcuts import render
from django.views.generic import ListView
from .models import Post

class PostList(ListView):
    model = Post
    template_name = "blog/index.html"

# def index(request):
#     posts = Post.objects.all().order_by('pk')
#     return render(
#         request,
#         'blog/index.html',
#         {
#             'posts' : posts,
#         },
#     )

이 때 서버를 실행해보면,

아무것도 뜨지 않는다. 이는,

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    <h1>blog</h1>

    {% for p in posts %}
        <hr/>
        <h3>><a href="{{ p.get_absolute_url }}">{{ p }}</a></h3>
        <h4>{{ p.create_at }}</h4>
        <p> {{ p.context }}</p>
    {% endfor %}
</body>
</html>

반복문에서 posts에 해당하는 dictionary가 없기 때문이다. 기본적으로 장고에서 제공하는 CBV는 dictionary 변수를 post_list로 정의한다. 따라서 이렇게 수정해주면 된다.

{% for p in post_list %}

또한, views.py 에서 template_name을 선언해주지 않고 template 파일 이름을 post_list 로 변경해주면 된다.

또, 순서도 정해줄 수 있다.

views.py

class PostList(ListView):
    model = Post
    ordering = '-pk'

CBV로 블로그 포스트 상세 페이지 만들기

마찬가지로 single_page도 클래스로 선언 가능하다.

views.py

from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Post

class PostDetail(DetailView):
    model = Post

# def single_post_page(request, pk):
#     post = Post.objects.get(pk=pk)
#     return render(
#         request,
#         'blog/single_page.html',
#         {
#             'post': post,
#         }
#     )

그리고 템플릿 파일 이름을 post_detail.html 로 변경한다.

마지막으로, url도 변경해주면 끝.

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('<int:pk>/', views.PostDetail.as_view()),
    # path('<int:pk>/', views.single_post_page),
    path('', views.PostList.as_view())
    # path('', views.index),
]

장고에서는 CBV로 제공하는 기능이 많기 때문에 편리하게 이용할 수 있고 이것을 직접 구현하기는 소모적이기 때문에 CBV를 사용하는 것을 권장한다!

Last updated

Was this helpful?