본문 바로가기
IT/Django

Django, 탬플릿 태그를 활용하여 DB에 등록된 데이터 출력 및 페이징네이션

by Cyber_ 2024. 4. 7.

0. 개요

DB에 데이터를 저장하는 부분은 생략합니다.

  • models.py
from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Question(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    subject = models.CharField(max_length = 200)
    content = models.TextField()
    create_date = models.DateTimeField()

    def __str__(self):
        return f'{self.subject}'

1. view.py

from django.shortcuts import render, get_object_or_404, redirect
from .models import Question
from django.utils import timezone
from .forms import QuestionForm, AnswerForm
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.contrib.auth.decorators import login_required


# Create your views here.
def index(request):
    """
    pybo 목록출력
    """
    question_list = Question.objects.all().order_by('-create_date')
    page = request.GET.get('page')
    paginator = Paginator(question_list, 10)
    
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        page = 1
        page_obj = paginator.page(page)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)
        
    leftIndex = (int(page) - 2)
    if leftIndex < 1:
        leftIndex = 1
        
    rightIndex = (int(page) + 2)
    
    if rightIndex > paginator.num_pages:
        rightIndex = paginator.num_pages
        
    custom_range = range(leftIndex, rightIndex + 1)
        
    
    context = {'question_list': question_list, 'page_obj': page_obj, 'paginator': paginator, 'custom_range': custom_range}
    return render(request, 'pybo/question_list.html', context)

1) render, get_object_or_404, redirect

  • render: Djnago에서 HTML 템플릿을 렌더링하고 HttpResponse 객체료 변환하는데 사용, 템플릿 파일과 함꼐 dict형태의 컨텍스트를 전달받아 최정족으로 사용자에게 HTML페이지를 반환
  • get_object_or_404: 모델에서 객체를 조회할 대 사용 만약 해당 객체가 존재하지 않을경우 자동으로 404 페이지를 반환
  • redierect: 사용자를 다른 URL로 리디렉션할 때 사용. URL이름, 절대 또는 상대 URL 경로를 인자로 받을 수 있으며, 해당 경로로 사용자를 이동시킴

2) Paginator, PageNotInteger, EmptyPage

  • Paginator: 객체 리스트를 페이지 단위로 나누어 관리하는데 사용. 데이터를 페이징 처리하여 한 번에 보여줄 데이터 양을 제한
  • PageNotInteger: 이 예외는 페이지 번호가 정수가 아닌 경우 발생
  • EmptyPage: 이 예외는 요청한 페이지에 객체가 없는 경우, 즉 요청한 페이지 번호가 범위를 벗어난 경우 발생

2. Django HTML

1) 장고 HTML이란?

  • Django에서 HTML은 템플릿 파일을 통해 구성. 템플릿은 Django 템플릿언어(DTL)을 사용하여 HTML과 같은 마크업 언어에 Python과 같은 동적 요소를 추가할 수 있게 해줍니다

2) 주요요소

  • 변수 : {{ variable_name }}, 전달된 컨테스트 내의 변수 값을 출력
  • 태크 : {% tag %}, 조건문, 반복문, 템플릿 상속등의 로직을 구현하는데 사용
  • 필터 : 변수에 파이프(|)룰 사용하여 필터를 적용할 수 있으며, 변수의 출력식을 변경할 때 사용

3) base.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Required meta tags-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <!-- Bootstrap CSS-->
    <link rel = "stylesheet" type = "text/css" href = "{% static 'bootstrap.min.css' %}">
    <!-- pybo CSS -->
    <link rel = "stylesheet" type = "text/css" href = "{% static 'style.css' %}">
    <title>Hello, pybo!</title>

    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
{% include "navbar.html" %}
<!-- 기본 템플릿 안에 삽입될 내용 Start -->
{% block content %}
{% endblock %}
<!-- 기본 템플릿 안에 삽입될 내용 End -->
<!-- BootStrap JS -->
</body>
</html>

3.question_list.html

{% extends 'base.html' %}
{% block content %}
<div class = "container my-3">
    <table class ="table table-striped table-hover">
        <thead>
        <tr calss = "thead-dark">
            <th>번호</th>
            <th>제목</th>
            <th>작성일시</th>
        </tr>
        </thead>
        <tbody>
        {% if page_obj %}
        {% for question in page_obj %}
        <tr>
            <td>{{ forloop.counter}}</td>
            <td>
                <a href = "{% url 'pybo:detail' question.id %}">
                    {{ question.subject}}
                </a>
            </td>
            <td> {{ question.create_date}}</td>
        </tr>
        {% endfor %}
        
        {% else %}
        <tr>
            <td colspan = "3"></td>
        </tr>
        {% endif %}
        </tbody>
    </table>

    
    <div>
        {% if page_obj.has_other_pages %}
        <ul style = "display:flex;list-style: none;">
            {% if page_obj.has_previous %}
            <li style = "margin:3px;"><a style = "text-decoration:none; color: blue;" href ="?page={{page_obj.previous_page_number}}">&#10094; Prev</a></li>
            {% endif %}

            {% for page in paginator.page_range %}
            {% if page == page_obj.number %}
                <li style="margin:3px"><a style="text-decoration:none; color: red;" href="?page={{page}}">{{page}}</a></li>
            {% else %}
                <li style="margin:3px"><a style="text-decoration:none; color: blue;" href="?page={{page}}">{{page}}</a></li>
            {% endif%}
            {% endfor %}

            {% if page_obj.has_next %}
            <li style = "margin:3px;"><a style = "text-decoration:none; color: blue;" href ="?page={{page_obj.next_page_number}}">&#10095; Next</a></li>
            {% endif %}
        </ul>
        {% endif %}
    </div>
    <a href ="{% url 'pybo:question_create' %}" class = "btn btn-priamry">
        질문등록하기
    </a>
</div>
{% endblock content%}