작정하고 Django 36강 - Articleapp 구현

_·2023년 12월 28일

작정하고 Django 강의

목록 보기
35/44

지금까지 CRUD에 해당하는 view를 작성했음

계정을 만들 때에는 단일 객체(single object)만 해당됐음

ex) detailView에서는 특정 계정의 정보

최종적으로 게시판 같은 형태의 Article을 만드는 것이 목표이기 때문에 여러 객체(multiple object)를 다룰 수 있는 view가 필요

여기서 나오는게 List view -> 장고에서 제공
추가적으로 pagination(페이지화 시킨다 -> 한 페이지에 몇 개의 게시글을 보여줄 것인지)

pagination

페이지에 객체를 생성한다는 의미
구글에서 여러 검색 페이지 '1 2 3 ...' 이 pagination을 의미
Infinite Scroll : 무한 스크롤 형식도 존재

ex) 페이스북, 인스타그램, 핀터레스트 등
구현하기 위해 추가적인 JavaScript 필요

ListView 의 형태

※ ListView 코드 위해 주요하게 사용할 템플릿의 두가지 html
article_List
page_obj

article_List

게시글의 리스트를 의미(아이템 꾸러미 역할)
이 안에 객체들의 각각의 장보를 다 담고 있어서 html에다 카드형 레이아웃을 가져온다면 각각 article_list를 다 뿌려주는 역할

page_obj

페이지를 만들어줄 때 생성하는 번호들을 만들어 그 페이지로 갈 수 있도록 링크를 만들어주는 역할

views.py 에 ArticleListView 작성

# articleapp/views.py
from msilib.schema import ListView

...
# 추가
class ArticleListView(ListView):
    model = Article
    context_object_name = 'article_List'
    template_name = 'articleapp/list.html'
    paginate_by = 5

urls.py에서 List로 향하는 라우팅 수정

기존에는 list에 대해서 임시로 TemplateView 라는 것을 사용했음.
이를 우리가 만든 ArticleListView 로 연결하여 수정한다.

from django.urls import path
from django.views.generic import TemplateView

from articleapp.views import ArticleCreateView, ArticleDetailView, ArticleUpdateView, ArticleDeleteView, ArticleListView

app_name = 'articleapp'

urlpatterns = [
    path('list/', ArticleListView.as_view(), name='list'), # 수정

    path('create/', ArticleCreateView.as_view(), name='create'),
    path('detail/<int:pk>', ArticleDetailView.as_view(), name='detail'),
    path('update/<int:pk>', ArticleUpdateView.as_view(), name='update'),
    path('delete/<int:pk>', ArticleDeleteView.as_view(), name='delete'),
]

픽섬에서 가져온 이미지들 전부 제거

articleapp/templates/articleapp/list.html 수정

<!--articleapp/templates/articleapp/list.html-->
...
<!--html 부분 수정-->
<div class="container">
    {% for article in article_list %}
    <a href=" {% url 'articleapp:detail pk=article.pk %}">
        <div>
            <img src="{{ article.image.url }}" alt="">
        </div>
    </a>
</div>
...

템플릿 내부에 snippets 디렉토리 생성

snippets는 코드 조각이라는 의미로 다음 코드를 따로 빼서 card.html 파일로 보관해줄 것
전체 카드의 레이아웃, 내용을 바꾸고 싶다면 이 card.html 만 수정하면 전체 반영

<!--templates/snippets/card.html-->
<div>
   <img src="{{ article.image.url }}" alt="">
</div>

list.html 수정

snippets에 있는 card.html을 가져온다
card.html 내부의 article이라는 것을 with 구문을 사용해 밖에 있는 article과 연결
즉, article_list로 부터 하나씩 뽑아올 article이
sinppets 내부 card.html의 article과 같다는 것을 명시해주는 것

<!--articleapp/templates/articleapp/list.html-->
...
<div class="container">
    {% for article in article_list %}
    <a href=" {% url 'articleapp:detail pk=article.pk %}">
        {% include 'snippets/card.html' with article=article %}
    </a>
</div>
...

게시글이 없을 경우

article_list는 게시글이 아예 없다면 존재하지 않기 때문에, article_list가 없을 경우 게시글이 없다는 것을 화면에 출력

...

    {% if article_list %}
    <div class="container">
        {% for article in article_list %}
        <a href=" {% url 'articleapp:detail' pk=article.pk %}">
            {% include 'snippets/card.html' with article=article %}
        </a>
        {% endfor %}
    </div>
    <script src="{% static 'js/magicgrid.js' %}"></script> <!--js 를 컨테이너 내부로 이동시키기--> 
    {% else %}
    <div class="text-center">
        <h1>No Articles YET! </h1>
    </div>
    {% endif %}

...

※ 게시글 만들 때
http://127.0.0.1:8000/articles/list/page=2

get 방식으로 page 값에 2를 넣어주면 다음 페이지로 이동함.

pagination 버튼 만들기

 {% if article_list %}
    <div class="container">
        {% for article in article_list %}
        <a href=" {% url 'articleapp:detail' pk=article.pk %}">
            {% include 'snippets/card.html' with article=article %}
        </a>
        {% endfor %}
    </div>
    <script src="{% static 'js/magicgrid.js' %}"></script> <!--js 를 컨테이너 내부로 이동시키기-->
    {% else %}
    <div class="text-center">
        <h1>No Articles YET! </h1>
    </div>
    {% endif %}

	<!-- 추가 -->
    {% include 'snippets/pagination.html' with page_obj=page_obj %}

snippets 안에다가 pagination.html 만들기

<!--templates/snippets/pagination.html-->
<div style="text-align: center; margin:1rem 0;">
  {% if page_obj.has_previous %} <!--현재 페이지 page_obj 객체가 이전 페이지를 가지고 있다면-->
  <!--get 방식으로 이전 페이지의 번호를 넘겨주면서 이전 페이지로 넘어가는 링크를 만들어줌-->
  <a href="{% url 'articleapp:list' %}?page={{ page_obj.previous_page_number }}"
    class="btn btn-secondary rounded-pill">
      {{ page_obj.previous_page_number }}
  </a>
  {% endif %}
  <!-- 현재 있는 페이지 -->
  <a href="{% url 'articleapp:list' %}?page={{ page_obj.number }}"
    class="btn btn-secondary rounded-pill active">
      {{ page_obj.number }}
  </a>
  {% if page_obj.has_next %} <!-- 다음 페이지가 있다면 -->
  <!-- 다음페이지로 향하는 링크 만들어주기-->
  <a href="{% url 'articleapp:list' %}?page={{ page_obj.next_page_number }}"
    class="btn btn-secondary rounded-pill active">
      {{ page_obj.next_page_number }}
  </a>
  {% endif %}
</div>

articleapp -> detail.html 수정

{% extends 'base.html'%}

{% block content %}

  <div>
    <div style="text-align: center; max-width: 700px; margin: 4rem auto;">

      <!--게시글의 제목-->
      <h1>
        {{ target_article.title }}
      </h1>
      <!-- 닉네임 표시 -->
      <h5>
        {{ target_article.writer.profile.nickname }}
      </h5>
      <hr>

      <!--게시글의 이미지-->
      <img style="width: 100%; border-radius: 1rem; margin: 2rem 0;"
              src=" {{ target_article.image.url }}" alt="">

      <!-- 게시글의 내용 -->
      <p>
        {{ target_article.content }}
      </p>

      <!-- 인증 과정 포함-->
      {% if target_article.writer == user %}
      <!-- 게시글 업데이트-->
      <a href="{% url 'articleapp:update' pk=target_article.pk %}"
      class="btn btn-primary rounded-pii col-3">
        Update
      </a>

      <!-- 게시글 삭제 -->
      <a href="{% url 'articleapp:delete' pk=target_article.pk %}"
      class="btn btn-danger rounded-pii col-3">
        Delete
      </a>
      {% endif %}
      <hr> <!-- 밑에 코멘트가 들어갈 공간 분리-->

    </div>
  </div>

{% endblock %}

commit

0개의 댓글