테이블 설계

블로그 앱 - 테이블 설계(Post 모델 클래스)

필드명 타입 제약 조건 설명
id Integer PK, Auto Increment기본 키(Primary Key)
title CharField(50) 포스트 제목(Primary Key)
slug SlugField(50) Unique포스트 제목 별칭
description CharField(100) Blank포스트 내용 한줄 설명
content TextField 포스트 내용 기록
created_date DateTimeField auto_now_add포스트를 생성한 날짜
modify_date DateTimeField auto_now포스트를 수정한 날짜

URL 설계

URL 패턴 뷰 이름 템플릿 파일명
/blog/ PostLV(ListView) post_all.html
/blog/post PostLV(ListView) post_all.html
/blog/post/slug/ PostDV(DetailView) post_detail.html
/blog/archive/ PostAV(ArchiveIndexView) post_archive.html
/blog/2018 PostYAV(YearArchiveView) post_archive_year.html
/blog/2018/sep PostMAV(MonthArchiveView) post_archive_month.html
/blog/2018/sep/09 PostDAV(DayArchiveView post_archive_day.html
/blog/today PostTAV(TodayArchiveView) post_archive_day.html

Models.py, Urls.py, Views.py 작성하기

모델 작성 (Models.py)

class Post(models.Model):
    title = models.CharField('TITLE', max_length = 50)
    # slug 칼럼은 제목의 별칭이라고 할 수 있음, unique 옵션을 추가해 특정 포스트를 검색시 기본키 대신 사용
    # allow_unicode 옵션을 추가하면 한글처리 가능  
    slug = models.SlugField('SLUG', unique = True, allow_unicode=True, help_text='one word for title alias')
    description = models.CharField('DESCRIPTION', max_length= 100, blank= True, help_text= 'simple description text.')
    content = models.TextField('CONTENT')
    # auto_now_add 속성은 객체가 생성될때의 시각을 자동으로 기록되게 함.  
    create_date = models.DateTimeField('Create Date', auto_now_add = True)
    # auto_now 속성은 객체가 데이터베이스에 저장될 때의 시각을 자동으로 기록되게 함.  
    modify_date = models.DateTimeField('Modify Date', auto_now = True)

    # 필드 속성외에 필요한 파라미터가 있으면 Meta 내부 클래스로 정의  
    class Meta:
        verbose_name = 'post'  # 테이블의 단수 별칭 
        verbose_name_plural = 'posts'  # 테이블의 복수 별칭
        # db에 저장되는 테이블의 이름을 'my_post'로 지정 
        # 미지정시 디폴트로 '앱명_모델클래스명(blog_post)'을 테이블명으로 지정
        db_table = 'my_post'  
        # 모델객체의 리스트 출력시 modify_date 칼럼을 기준으로 내림차순 정렬
        ordering = ('-modify_date',) 

	# 객체의 문자열을 객체.title 속성으로 표시되도록 함 
    def __str__(self):
        return self.title

	# 이 메소드가 정의된 객체를 지칭하는 URL을 반환. 
    def get_absolute_url(self):
        return reverse('blog:post_detail', args = (self.slog, ))
        
	# modify_date 칼럼을 기준으로 이전 포스트 반환  
    def get_previous_post(self):
        return self.get_previous_by_modify_date()
         
	# modify_date 칼럼을 기준으로 다음 포스트 반환  
    def get_next_post(self):
        return self.get_next_by_modify_date()

admin.py에 정의한 모델 등록

blog/admin.py

from django.contrib import admin
from blog.models import  Post


class PostAdmin(admin.ModelAdmin):
	# Post 객체를 보여줄때, title과 modify_date를 화면에 출력하라고 지정.  
    list_display = ('title', 'modify_date')
    # modify_date 칼럼을 사용하는 필터 사이드바를 보여주도록 지정  
    list_filter = ('modify_date',)
    # 검색 박스를 표시하고, 입력된 단어는 title과 content칼럼에서 검색하도록 함
    search_fields = ('title', 'content')
    # slug필드는 title 필드를 사용해 미리 채워지도록 함.  
    prepopulated_fields = { 'slug' : ('title',)}

admin.site.register(Post, PostAdmin)

URLconf 작성 (urls.py)

mysite/urls.py

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

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

blog/urls.py

from django.urls import path
from blog.views import *

app_name = 'blog'

urlpatterns = [
    # Example : /
    path('', PostLV.as_view(), name='index'),
    # Example : /post/
    path('post/', PostLV.as_view(), name='post_list'),
    # Example : /post/slug/
    path('post/<slug:slug>/', PostDV.as_view(), name='post_detail'),
    # Example : /archive/
    path('archive/', PostAV.as_view(), name='post_archive'),

    # Example : /2018/
    path('<int:year>/', PostYAV.as_view(), name='post_year_archive'),
    # Example : /2018/sep/
    path('<int:year>/<int:month>/', PostMAV.as_view, name='post_month_archive'),
    # Example : /2018/sep/10
    path('<int:year>/<int:month>/<int:day>/', PostDAV.as_view, name='post_day_archive'),

    # Example : /today/
    path('today/', PostTAV.as_view, name = 'post_today_archive')
]

뷰 코딩하기

blog/views.py

from django.shortcuts import render
from django.views.generic import ListView, DetailView
from django.views.generic.dates import ArchiveIndexView, YearArchiveView, MonthArchiveView
from django.views.generic.dates import DayArchiveView, TodayArchiveView

from blog.models import Post


# ListView
class PostLV(ListView):
    model = Post
    template_name = 'blog/post_all.html'  # 템플릿명을 지정하지 않으면 디폴트 템플릿 파일명은 'blog/post_list.html'이 됨.
    context_object_name = 'posts'
    paginate_by = 2


# DetailView
class PostDV(DetailView):
    model = Post


# ArchiveView
class PostAV(ArchiveIndexView):
    model = Post
    date_field = 'modify_date'


class PostYAV(YearArchiveView):
    model = Post
    date_field = 'modify_date'
    make_object_list = True


class PostMAV(MonthArchiveView):
    model = Post
    date_field = 'modify_date'


class PostDAV(DayArchiveView):
    model = Post
    date_field = 'modify_date'


class PostTAV(TodayArchiveView):
    model = Post
    date_field = 'modify_date'

  • ArchiveIndexView 제네릭뷰는 테이블로부터 객체 리스트를 가져와, 날짜 필드를 기준으로 최신 객체를 먼저 출력.
  • YearArchiveView 제네릭뷰는 테이블로부터 날짜 필드의 연도를 기준으로 객체 리스트를 가져와, 그 객체들이 속한 월을 리스트로 출력
  • MonthArchiveView 제네릭뷰는 테이블로부터 날짜 필드의 연월을 기준으로 객체 리스트를 가져와, 그 리스트를 출력
  • DayArchiveView 제네릭뷰는 테이블로부터 날짜 필드의 연원일을 기준으로 객체 리스트를 가져와 그 리스트를 출력
  • TodayArchiveView 제네릭뷰는 테이블로부터 날짜 필드가 오늘인 객체 리스트를 가져와, 그 리스트를 출력함.

템플릿 코드 작성하기

blog/templates/blog/post_all.html

<!DOCTYPE html>
<html>
<head>
    <title> Post List </title>
</head>
<body>
<h1> Blog List </h1>

{% for post in posts %}
<h2><a href='{{ post.get_absolute_url }}'> {{ post.title }} </a></h2>

<p> {{ post.description }} </p>
{% endfor %}

<div>
    <span>
    <!-- page_obj는 장고의 Page객체가 들어있는 컨텍스트 변수, 현재 페이지를 기준으로 이전페이지가 있는지 확인 -->
        {% if page_obj.has_previous %}
            <a href ="?page = {{ page_obj.previous_page_number }}">Previous Page</a>
        {% endif %}

        Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}

        {% if page_obj.has_next %}
            <a href = "?page= {{ page_obj.next_page_number }}">Next Page</a>
        {% endif %}
    </span>
</div>

</body>
</html>
  • 템플릿에서 URL 추출 함수 템플릿 파일에서 URL을 추출하는 문법은 2가지 있음.
    get_absolute_url() 메소드를 이용하는 방법과 {% url %} 템플릿 태그를 사용하는 방법.
    {% url %} 태그는 직접 태그의 인자로 URL 패턴명을 사용하는 반면, get_absolute_url() 메소드에서는 간접적으로 URL 패턴명을 사용.
    get_absolute_url() 메소드는 모델 클래스의 메소드로 정의되어 있어야 사용 가능함. 이 메소드를 정의할때 reverse() 함수를 사용하고, reverse()함수의 인자로 URL 패턴명을 사용하고 있음.
    아래의 두 문장은 동일한 문장임
    <a href = '{{ post.get_absolute_url }}'> {{ post.title }} </a>   
    <a href = "{% url 'blog_post_detail' post.slug %}"> {{ post.title }} </a>  
    

전체 프로그램 소스
참조