장고의 원리를 이해하기엔 FBV가 낫겠지만, 편의성은 CBV가 나음.
FBV: Fuction based view로 함수에 기반을 둔 방법
CBV: Class based view로 장고가 제공하는 클래스를 활용해서 구현하는 방법
함수기반의 방식은 url.py의 request를 받고 이를 view.py에서 object함수로 불러온다.
url.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('<int:pk>/', views.single_post_page),
]
view.py
from django.shortcuts import render
from .models import Post
def index(request):
posts = Post.objects.all().order_by('-pk')
context = {'posts' : posts}
return render(request,'blog/index.html',context)
def single_post_page(request, pk):
post = Post.objects.get(pk=pk)
context = {'post' : post}
return render(request,'blog/single_post_page.html',context)
view.py에서 쟝고에서 제공하는 ListView 및 DetailView 클래스를 활용한다. url.py에서는 as_view() 클래스 매써드를 이용해서 클래스가 view기능을 수행할 수 있도록 한다. (장고 공식문서)
url.py
from django.urls import path
from . import views
urlpatterns = [
path('',views.PostList.as_view()), #url 패턴이 blog일 때 PostList 클래스로 처리하도록 수정, 클래스에 as_view매써드를 붙혀 view함수의 기능을 수행토록 조정
path('<int:pk>/', views.PostDetail.as_view()),
]
view.py
from .models import Post
from django.views.generic import ListView, DetailView #ListView를 불러옴.
class PostList(ListView):
model = Post #이런 경우, 템플릿 디폴트값은 post_list.html이 됨.
template_name = 'blog/index.html' #템플릿 디폴트값을 쓰지 않을 경우 지정
ordering = '-created_at'
class PostDetail(DetailView):
model = Post
model.py
from django.db import models
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
head_image = models.ImageField(upload_to='blog/images/%Y/%m/%d/', blank=True)
file_upload = models.FileField(upload_to='blog/files/%Y/%m/%d/', blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'[{self.pk}]{self.title}'
def get_absolute_url(self):
return f'/blog/{self.pk}/'
템플릿에서 ListView로 만든 클래스의 모델 객체를 사져올 때 object_list명령어를 사용하면 됨. 또는 Post 모델 사용했으니, post_list라고 써도 인식함.
{% for post in object_list %}
<div class="card mb-4">
{% if post.head_image %}
<img class="card-img-top" src="{{ post.head_image.url }}" alt="{{ post }} head image">
{% else %}
<img class="card-img-top" src="https://picsum.photos/seed/{{ post.id }}/800/200" alt="random image">
{% endif %}
<div class="card-body">
<h2 class="card-title">{{ post.title }}</h2>
<p class="card-text">{{ post.content }}</p>
<a href="{{ post.get_absolute_url }}" class="btn btn-primary">Read More →</a>
</div>
<div class="card-footer text-muted">
Posted on {{ post.created_at }} by
<a href="#">작성자명 쓸 위치(개발예정)</a>
</div>
</div>
{% endfor %}
from .models import Post
from django.views.generic import ListView, DetailView #ListView를 불러옴.
class PostList(ListView):
model = Post #이런 경우, 템플릿 디폴트값은 post_list.html이 됨.
#template_name = 'blog/index.html'
ordering = '-created_at'
class PostDetail(DetailView):
model = Post
CBV에서는 _list 및 _detail로 문서 이름을 만들어주면 코드의 양을 줄일 수 있다.