🚀

DRF(django-rest-framework)のAPIViewでページネーションを使う

2022/08/23に公開

概要

DRFのAPIViewでページネーションを使うときに思ったより苦戦したでその時のメモ。

動くコードは以下にコミットしてあります。(ファイル名が雑なのは気にしないでください)
https://github.com/nelsia/drf_pagination_apiview_sample

注意事項

以下のライブラリバージョンで動作確認しています。

Django==4.1
djangorestframework==3.13.1

djangoプロジェクトの作成

まずは、djangoのプロジェクト作成をします。
ここのやり方はそれぞれの環境に合わせて適宜作成してください。
以下のコマンドはMacで実行しています。

$ mkdir drf_pagination_apiview
$ cd drf_pagination_apiview

$ python -m venv .venv
$ source .venv/bin/activate
$ pip instal django djangorestframework django-cors-headers

$ django-admin startproject config .
$ python manage.py startapp myapp

djangoの初期設定

settings.py

django-rest-framework、corsheaders、appの設定を追記します。

config/settings.py
~~~ 省略 ~~~

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # 以下を追記
    'corsheaders',
    'rest_framework',
    'myapp',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', # 追記
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# 追記
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 10, # デフォルトで10レコードずつ取得
}

~~~ 省略 ~~~

config/urls.pyを編集

myappで実装するviewsをあらかじめimportしておく。

config/urls.py
from django.contrib import admin
from django.urls import path, include # includeを追記

from myapp.urls import app_urls # 追記

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(app_urls)), # 追記
]

myappの設定

ここにAPIViewでページネーションをする実装をしていきます。

models.pyを編集

今回のサンプルで使用するモデルを作成。
特に意味はないが2つカラムを作ってみた。

myapp/models.py
from django.db import models


class DRFPaginationModel(models.Model):
    col1 = models.CharField(max_length=30)
    col2 = models.CharField(max_length=30)

    def __str__(self):
        return self.col1

serializers.pyの作成

ModelSerializerを使ってdjangoのモデルからシリアライザを作成

myapp/serializers.py
from rest_framework import serializers

from myapp.models import DRFPaginationModel


class DRFPaginationSerializer(serializers.ModelSerializer):
    class Meta:
        model = DRFPaginationModel
        fields = "__all__"

views.pyを編集

ここが重要な部分。
APIViewLimitOffsetPaginationを継承したクラスを作成し、paginate_querysetに渡すことでページネーションができるらしい。

myapp/views.py
from rest_framework.views import APIView
from rest_framework.pagination import LimitOffsetPagination # ページネーションのクラス

from myapp.models import DRFPaginationModel
from myapp.serializers import DRFPaginationSerializer


class DRFPaginationSampleView(APIView, LimitOffsetPagination):
    def get(self, request):
        # 今回はモデルから全データを取得
        q = DRFPaginationModel.objects.all()
        
        results = self.paginate_queryset(q, request, view=self)
	t = DRFPaginationSerializer(results, many=True)

        # t.dataでpaginationされたデータにアクセスできる
        res = {
            "data": t.data,
            "test": "このように好きな値とかもセットできる"
        }

        return self.get_paginated_response(res)

urls.pyを作成

作成したViewをURLで繋ぎこむ。

myapp/urls.py
from django.urls import path, include

from myapp.views import DRFPaginationSampleView


app_urls = [
    path("paginationsample/", DRFPaginationSampleView.as_view()),
]

サンプルデータをロード

リポジトリに1000レコードのサンプルデータを用意しているので必要であればロードしてください。
※リポジトリ内のsqliteには予めデータが読み込まれています

$ python manage.py loaddata dump.json

APIを試す

$ python manage.py runserver

以下のURLにアクセス
http://127.0.0.1:8000/api/paginationsample/
今回はsettings.pyにPAGE_SIZEを10と設定したので10件ずつ帰ってくる。

{
    "count": 1000,
    "next": "http://127.0.0.1:8000/api/paginationsample/?limit=10&offset=10",
    "previous": null,
    "results": {
        "data": [
            {
                "id": 1,
                "col1": "C1-0",
                "col2": "C2-0"
            },
            {
                "id": 2,
                "col1": "C1-1",
                "col2": "C2-1"
            },
		~~~ 省略 ~~~
            {
                "id": 9,
                "col1": "C1-8",
                "col2": "C2-8"
            },
            {
                "id": 10,
                "col1": "C1-9",
                "col2": "C2-9"
            }
        ],
        "test": "このように好きな値とかもセットできる"
    }
}

参考

クエリパラメータを書き換えると任意の位置から指定したレコード数取得できる

  • limit・・・取得するレコード数
  • offset・・・取得を開始する位置

limitとoffsetの例

  • 15レコード目から14件取得したい
    • limit=14
    • offset=15

最後に

DRFはシンプルなAPIは簡単に作れる反面、細かいことをやろうとするとよく苦戦するので、最小限で動くサンプルは今後も残して行きたいなと思います。

Discussion