Django ViewClass 2-6) Pagination, Template filter

Turtleยท2023๋…„ 12์›” 18์ผ
0
post-thumbnail

๐Ÿ“ŒPagination

  • ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์ด์ง€๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ์กฐํšŒํ•˜๋Š” ๋กœ์ง์ด๋‚˜ ๋ชจ๋“ˆ

    • Django์—์„œ๋Š” Paginator๋ฅผ ์ œ๊ณต
    • Paginator(QuerySet, ํ•œ ํŽ˜์ด์ง€๋‹น ๋ณด์—ฌ์งˆ ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜) ํ˜•ํƒœ๋กœ ์ดˆ๊ธฐํ™”
    • get_page(ํŽ˜์ด์ง€๋ฒˆํ˜ธ) ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉ
    • ListView์—์„œ๋Š” paginate_by ํ•„๋“œ๋กœ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„
  • Django๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋งค๊ฒจ์ง„ ๋ฐ์ดํ„ฐ, ์ฆ‰ "์ด์ „/๋‹ค์Œ" ๋งํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์— ๊ฑธ์ณ ๋ถ„ํ• ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜๋Š” ์ƒ์œ„ ์ˆ˜์ค€ ๋ฐ ํ•˜์œ„ ์ˆ˜์ค€ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

  • Page Class๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฐธ๊ณ ๋ฌธ์„œ - Django Pagination

๐Ÿ“ŒPaginating a ListView

  • django.views.generic.list.ListView๋Š” ํ‘œ์‹œ๋œ ๋ชฉ๋ก์— ํŽ˜์ด์ง€๋ฅผ ๋งค๊ธฐ๋Š” ๊ธฐ๋ณธ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค. ๋ทฐ ํด๋ž˜์Šค์— paginate_by ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ํ•œ ํŽ˜์ด์ง€๋‹น ๋ณด์—ฌ์ง€๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
from django.views.generic import ListView
from myapp.models import Contact

class ContactListView(ListView):
    paginate_by = 2
    model = Contact
{% for contact in page_obj %}
    {# Each "contact" is a Contact model object. #}
    {{ contact.full_name|upper }}<br>
    ...
{% endfor %}

<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; first</a>
            <a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">next</a>
            <a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
        {% endif %}
    </span>
</div>
  • ListView๋ฅผ ํ†ตํ•ด์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฆฌํ„ดํ•  ๋•Œ ๋ณ€์ˆ˜๋ช…์„ ์ง€์ •ํ•˜๋ฉด ํ…œํ”Œ๋ฆฟ์—์„œ ๊ทธ ๋ณ€์ˆ˜๋ช…์„ ์‚ฌ์šฉํ•ด์•ผํ•˜์ง€๋งŒ ๋งŒ์•ฝ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด page_obj๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ดํ„ฐ๋ ˆ์ด์…˜์„ ์ˆ˜ํ–‰ํ•ด์•ผ ์ •์ƒ์ ์œผ๋กœ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ๊ตฌํ˜„์ด ๋œ๋‹ค.

๐Ÿ“ŒUsing Paginator in a view function

from django.core.paginator import Paginator
from django.shortcuts import render
from myapp.models import Contact


def listing(request):
    contact_list = Contact.objects.all()
    paginator = Paginator(contact_list, 25)  # Show 25 contacts per page.
    
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)
    return render(request, "list.html", {"page_obj": page_obj})

๐Ÿ“Œ์ ์šฉ

  • page-range๋ฅผ ์ ์šฉํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ๋Š˜์–ด๋‚  ๊ฒฝ์šฐ ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ฆฌํ„ดํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ํ…œํ”Œ๋ฆฟ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render, HttpResponseRedirect, redirect
from django.views.generic import TemplateView, CreateView, UpdateView, DeleteView, ListView, DetailView, FormView
from .models import Task, ChecklistItem
from django.utils import timezone
from django.core.paginator import Paginator
from django.urls import reverse_lazy

class TaskListView(TemplateView):
    template_name = 'pages/task_list.html'
    
    def get_context_data(self, **kwargs):
        # tasks โ†’ QuerySet(๋ฆฌ์ŠคํŠธ ํ˜•ํƒœX)
        tasks = Task.objects.filter(due__gte=timezone.now()).order_by('-due').all()
        paginator = Paginator(tasks, 4)
        page_number = self.request.GET.get('page', 1)
        paging = paginator.get_page(page_number)
        return {
            'paging' : paging,
        }
<div class="row mt-4">
    <nav class="col-12">
        <ul class="pagination justify-content-center">
            {% if paging.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page={{paging.previous_page_number}}">์ด์ „</a>
            </li>
            {% endif %}
			
          	<!-- Paginator.page_range A 1-based range iterator of page numbers, e.g. yielding [1, 2, 3, 4].-->
            {% for page in paging|slice_visible_pages %}
            {% if paging.number == page %}
                <li class="page-item active">
                {% else %}
                <li class="page-item"></li> 
                {% endif %}
                <a class="page-link" href="?page={{page}}">{{page}}</a>
                </li>
            {% endfor %}

            {% if paging.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{paging.next_page_number}}">๋‹ค์Œ</a>
            </li>
            {% endif %}
        </ul>
    </nav>
</div>

๐Ÿ“Œpage_range์˜ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ ํ•„ํ„ฐ ์ ์šฉ

โ‘ . templatetags ํด๋” ์ƒ์„ฑ(์ด ๋•Œ, ์ผ๋ฐ˜ ํด๋”๊ฐ€ ์•„๋‹ˆ๋ผ Python Packages๋กœ ์ƒ์„ฑ)
โ‘ก. templatetags ํ•˜์œ„์— pagination_tags.py ํŒŒ์ผ ์ƒ์„ฑ

from django import template
from django.core.paginator import Page

register = template.Library()

@register.filter(name="slice_visible_pages")
def slice_visible_pages(paging: Page):
    min_page = int((paging.number - 1) / 10) * 10 + 1
    
    # ์Œ์ˆ˜๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘๊ฐ’์„ ๋ฌด์กฐ๊ฑด 1๋กœ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•จ
    min_page = max(min_page, 1)
    max_page = min(min_page + 9, paging.paginator.num_pages)
    return range(min_page, max_page+1)

์ฐธ๊ณ  ์ž๋ฃŒ - Django Custom Template tags and filters

Registering custom filters

from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter(name="cut")
def cut(value, arg):
    return value.replace(arg, "")
  • custom template tags and filters๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ˜•์‹์œผ๋กœ ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋‹ค.
  • ์ด๋ฆ„์„ ์ง€์ • ํ›„ ์‚ฌ์šฉํ•  ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ด๋™ ํ›„ {% load %} ๋ฌธ์„ ์ด์šฉํ•ด์„œ ๋กœ๋“œํ•œ ํ›„ or์„ ์ด์šฉํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด์•ผ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
{% load pagination_tags %}

...

{% for page in paging|slice_visible_pages %}

0๊ฐœ์˜ ๋Œ“๊ธ€