【Django】Paginatorを継承してシンプルなページ付けの実装
今回はDjangoのクラスであるPaginatorを継承してTODOアプリのページ付けを実装していきたいと思います。
ここではシンプルなページ付けを実装するので、より複雑な処理を行うページ付けに関しては「django paginator」と検索し深堀してください。
TODOアプリに関しては過去に実装したものを使用します。MVTのソースコードを掲載しておきますが詳しく知りたい場合は以下のリンクに飛んでください。
実行環境 |
---|
Windows Subsystem for Linux |
Python 3.6.8 |
pip 9.0.1 |
使用ライブラリ | ライセンス |
---|---|
Django==2.2.6 | BSD |
# app/todo/urls.py
from django.urls import path
from . import views
app_name = 'todo'
urlpatterns = [
path('', views.index, name='index'),
path('todo/<str:category>/', views.todo_category, name='todo_category'),
]
# app/todo/models.py
from django.db import models
class Category(models.Model):
title = models.CharField('カテゴリー', max_length=20)
def __str__(self):
return self.title
class Todo(models.Model):
title = models.CharField('タイトル', max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
def __str__(self):
return self.title
# app/todo/views.py
from django.shortcuts import render
from .models import Todo, Category
def index(request):
todo = Todo.objects.order_by('title')
return render(request, 'todo/index.html', {'todo': todo})
def todo_category(request, category):
category = Category.objects.get(title=category)
todo = Todo.objects.filter(category=category).order_by('title')
return render(request, 'todo/index.html', {'todo': todo, 'category': category })
<!-- app/todo/templates/todo/base.html -->
<!doctype html>
<html>
<head>
<title>TODO</title>
</head>
<body>
<h2>カテゴリー</h2>
<ul>
<a href="{% url 'todo:index' %}">
<li>トップ</li>
</a>
{% for category in category_list %}
<a href="{% url 'todo:todo_category' category %}">
<li>{{ category }}</li>
</a>
{% endfor %}
</ul>
{% block content %}
{% endblock %}
</body>
</html>
<!-- app/todo/templates/todo/index.html -->
{% extends 'todo/base.html' %}
{% block content %}
<h2>TODOリスト</h2>
{% if category %}
<div>
<h2 >カテゴリー: {{ category.title }}</h2>
</div>
{% endif %}
{% for todos in todo %}
<ul>
<li>{{ todos.title }}--{{ todos.created_at }}</li>
</ul>
{% endfor %}
{% endblock %}
Paginatorを使うためにはDjango側でクラス定義されているfrom django.core.paginator import Paginatorという要素をインポートし一覧表示など実装している関数に渡します。
# app/todo/views.py
from django.shortcuts import render
from django.core.paginator import Paginator # ←ここ
from .models import Todo, Category
def index(request):
todo = Todo.objects.order_by('title')
"""TODOリストでは3つずつ表示させる"""
paginator = Paginator(todo, 3)
page = request.GET.get('page')
todo = paginator.get_page(page)
return render(request, 'todo/index.html', {'todo': todo})
def todo_category(request, category):
category = Category.objects.get(title=category)
todo = Todo.objects.filter(category=category).order_by('title')
"""カテゴリを選択したら1つずつ表示させる"""
paginator = Paginator(todo, 1)
page = request.GET.get('page')
todo = paginator.get_page(page)
return render(request, 'todo/index.html', {'todo': todo, 'category': category })
一覧表示用とカテゴリ一覧用とそれぞれ分けてページ付けを行っています。
テンプレートでは新しくpage.htmlを作成し、作成したpage.htmlをincludeテンプレートタグとしてindex.html
に渡します。
<!-- app/todo/templates/todo/page.html -->
<div class="pagination">
<span class="step-links">
{% if todo.has_previous %}
<a href="?page=1">&laquo;</a>
<a href="?page={{ todo.previous_page_number }}">前へ</a>
{% endif %}
<span class="current">
{{ todo.number }} / {{ todo.paginator.num_pages }}
</span>
{% if todo.has_next %}
<a href="?page={{ todo.next_page_number }}">次へ</a>
<a href="?page={{ todo.paginator.num_pages }}">»</a>
{% endif %}
</span>
</div>
<!-- app/todo/templates/todo/index.html -->
{% extends 'todo/base.html' %}
{% block content %}
<h2>TODOリスト</h2>
{% if category %}
<div>
<h2 >カテゴリー: {{ category.title }}</h2>
</div>
{% endif %}
{% for todos in todo %}
<ul>
<li>{{ todos.title }}--{{ todos.created_at }}</li>
</ul>
{% endfor %}
<!-- ここ -->
{% include 'todo/page.html' %}
{% endblock %}
それでは確認をしてみましょう。
カテゴリ一覧
しっかりページが遷移されれば成功です。
シンプルなページ付けの実装となりましたが、見えないページ一覧を減らすことでメモリ使用量の削減にも繋がると思うので無駄ではないですね。
それでは以上となります。
ご覧いただきありがとうございました。