본문 바로가기

Django

[Django] Blog 앱 개발

뼈대 만들기

블로그 앱에 대한 설정 클래스를 settings.py에 등록한다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bookmark.apps.BookmarkConfig',
    'blog.apps.BlogConfig', # 추가
]

 

models.py 수정

from django.db import models
from django.urls import reverse


class Post(models.Model):
    title = models.CharField(verbose_name='TITLE', max_length=50)
    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')
    create_dt = models.DateTimeField('CREATE DATE', auto_now_add=True)
    modify_dt = models.DateTimeField('MODIFY DATE', auto_now=True)

    class Meta:
        verbose_name = 'post'
        verbose_name_plural = 'posts'
        db_table = 'blog_posts'
        ordering = ('-modify_dt',)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('blog:post_detail', args=(self.slug,))

    def get_previous(self):
        return self.get_previous_by_modify_dt()

    def get_next(self):
        return self.get_next_by_modify_dt()

위 코드에서 필요한 부분 몇가지만 설명 하겠다.

CharField : 한 줄로 입력된다.

Slug : 페이지나 포스트를 설명하는 핵심 단어의 집합.

SlugField : 보통 제목의 단어들을 하이픈으로 연결해 생성하며, URL에서 pk대신 사용되는 경우가 많다. pk를 사용하면 숫자로만 되어 있어 그 내용을 유추하기 어렵지만, 슬러그를 사용하면 보통의 단어들이라서 이해하기 쉽다.

TextField : 여러 줄 입력이 가능.

DateTimeField : 날짜와 시간을 입력. auto_now 속성은 시각을 자동으로 기록하게 한다.

Meta : 필드 속성 외에 필요한 파라미터가 있으면, Meta 내부 클래스로 정의한다.

 

admin.py 수정

앞서 정의한 테이블도 admin 사이트에 보이도록 수정한다.

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


@admin.register(Post)
class PostAdmin(admin.ModelAdmin): 
    list_display  = ('id', 'title', 'modify_dt') 
    list_filter   = ('modify_dt',) 
    search_fields = ('title', 'content') 
    prepopulated_fields = {'slug': ('title',)}

수정 했다면 반영해주자

확인해 보면 정상적으로 반영된 것을 볼 수 있다.

 

urls.py 수정

블로그 앱의 mysite/urls.py와 blog/urls.py 2개의 파일에 코딩하고 2장에서 작성했던 북마크앱의 url도 2개의 파일로 수정한다. 이와같이 두개의 파일을 각각 수정해 주는 것은 확장성 측면에서 유리하다.

# mysite/urls.py

from django.contrib import admin
from django.urls import path, include
# from bookmark.views import BookmarkLV, BookmarkDV


urlpatterns = [
    path('admin/', admin.site.urls),
    path('bookmark/', include('bookmark.urls')),
    path('blog/', include('blog.urls')),
    # class-based views
    # path('bookmark/', BookmarkLV.as_view(), name='index'),
    # path('bookmark/<int:pk>/', BookmarkDV.as_view(), name='detail'),
]

# bookmark/urls.py

from django.urls import path
from bookmark.views import BookmarkLV, BookmarkDV


app_name = 'bookmark'
urlpatterns = [
    path('', BookmarkLV.as_view(), name='index'),
    path('<int:pk>/', BookmarkDV.as_view(), name='detail'),
]

# blog/urls.py

from django.urls import path, re_path
from blog import views


app_name = 'blog'
urlpatterns = [
    path('', views.PostLV.as_view(), name='index'),
    path('post/', views.PostLV.as_view(), name='post_list'),
    re_path(r'^post/(?P<slug>[-\w]+)/$', views.PostDV.as_view(), name='post_detail'),
    path('archive/', views.PostAV.as_view(), name='post_archive'),
    path('archive/<int:year>/', views.PostYAV.as_view(), name='post_year_archive'),
    path('archive/<int:year>/<str:month>/', views.PostMAV.as_view(), name='post_month_archive'),
    path('archive/<int:year>/<str:month>/<int:day>/', views.PostDAV.as_view(), name='post_day_archive'),
    path('archive/today/', views.PostTAV.as_view(), name='post_today_archive'),

]

 

views.py 수정

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

from blog.models import Post


#--- ListView
class PostLV(ListView):
    model = Post
    template_name = 'blog/post_all.html'
    context_object_name = 'posts'
    paginate_by = 2


#--- DetailView
class PostDV(DetailView):
    model = Post


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


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


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


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


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

제네릭 뷰의 몇가지만 설명하겠다.

ListView : 테이블로부터 객체 리스트를 가져와 그 리스트를 출력한다.

DetailView : 테이블로부터 특정 객체를 가져와 그 객체의 상세 정보를 출력한다. 여기서 특정 객체를 조회하기 위한 키는 기본 키 대신 slug 속성을 사용 하고 있다.

ArchiveIndexView : 테이블로 부터 객체 리스트를 가져와, 날짜 필드를 기준으로 최신 객체를 먼저 출력한다.

YearArchiveView : 테이블로부터 날짜 필드의 연도를 기준으로 객체 리스트를 가져와 그 객체들이 속한 월을 리스트로 출력한다.

MonthArchiveView : 테이블로부터 날짜 필드의 연월을 기준으로 객체 리스트를 가져와 그 리스트를 출력한다.

DayArchiveView : 테이블로부터 날짜 필드의 연월일을 기준으로 객체 리스트를 가져와 그 리스트를 출력한다.

TodayArchiveView : 날짜 필드가 오늘인 객체 리스트를 가져와 그 리스트를 출력한다.

 

Template 

# post_all.html
<h1>Blog List</h1>
<br>

{% for post in posts %}
    <h3><a href='{{ post.get_absolute_url }}'>{{ post.title }}</a></h3>
    {{ post.modify_dt|date:"N d, Y" }}
    <p>{{ post.description }}</p>
{% endfor %}

<br>

<div>
    <span>
        {% if page_obj.has_previous %}
            <a href="?page={{ page_obj.previous_page_number }}">PreviousPage</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 }}">NextPage</a>
        {% endif %}
    </span>

</div>

# post_archive_day.html
<h1>Post Archives for {{ day|date:"N d, Y" }}</h1>

<div>
    <ul>
        {% for post in object_list %}
        <li>{{ post.modify_dt|date:"Y-m-d" }}&nbsp;&nbsp;&nbsp;
        <a href="{{ post.get_absolute_url }}"><strong>{{ post.title }}</strong></a></li>
        {% endfor %}
    </ul>
</div>

# post_archive_month.html
<h1>Post Archives for {{ month|date:"N, Y" }}</h1>

<div>
    <ul>
        {% for post in object_list %}
        <li>{{ post.modify_dt|date:"Y-m-d" }}&nbsp;&nbsp;&nbsp;
        <a href="{{ post.get_absolute_url }}"><strong>{{ post.title }}</strong></a></li>
        {% endfor %}
    </ul>
</div>

# post_archive_year.html

<h1>Post Archives for {{ year|date:"Y" }}</h1>

<ul>
    {% for date in date_list %}
    <li style="display: inline;">
        <a href="{% url 'blog:post_month_archive' year|date:'Y' date|date:'b' %}">{{ date|date:"F" }}</a></li>
    {% endfor %}
</ul>
<br>

<div>
    <ul>
        {% for post in object_list %}
        <li>{{ post.modify_dt|date:"Y-m-d" }}&nbsp;&nbsp;&nbsp;
        <a href="{{ post.get_absolute_url }}"><strong>{{ post.title }}</strong></a></li>
        {% endfor %}
    </ul>
</div>

# post_archive.html
<h1>Post Archives until {% now "N d, Y" %}</h1>
<ul>
    {% for date in date_list %}
    <li style="display: inline;">
        <a href="{% url 'blog:post_year_archive' date|date:'Y' %}">Year-{{ date|date:"Y" }}</a></li>
    {% endfor %}
</ul>
<br/>

<div>
    <ul>
        {% for post in object_list %}
        <li>{{ post.modify_dt|date:"Y-m-d" }}&nbsp;&nbsp;&nbsp;
        <a href="{{ post.get_absolute_url }}"><strong>{{ post.title }}</strong></a></li>
        {% endfor %}
    </ul>
</div>

# post_detail.html
<h2>{{ object.title }}</h2>

<p>
    {% if object.get_previous %}
    <a href="{{ object.get_previous.get_absolute_url }}" title="View previous post">
        &laquo;-- {{ object.get_previous }}
    </a>
    {% endif %}

    {% if object.get_next %}
    | <a href="{{ object.get_next.get_absolute_url }}" title="View next post">
    {{ object.get_next }} --&raquo;
    </a>
    {% endif %}
</p>

<p>{{ object.modify_dt|date:"j F Y" }}</p>
<br>

<div>
    {{ object.content|linebreaks }}
</div>

 

 

'Django' 카테고리의 다른 글

[Django] Bookmark 앱, Blog 앱 개선하기  (0) 2022.07.22
[Django] 첫 페이지 만들기  (0) 2022.07.22
[Django] 가상환경 설정, Bookmark 앱 개발  (0) 2022.07.20
[Django] 장고 파헤쳐보기  (0) 2022.07.20
[Django] What is Django?  (0) 2022.07.20