背景
graphene-django
は簡単に取得件数を制限(SQLでいうlimit
)できるようになっておらず、全件取得できてしまう。
そこで1回のクエリで取得できる件数の制限を行えるようにする。
動作環境
- Python3
- django 2.0.1
- graphene-django 2.0.0
- django-filter 1.1.0
コード
基本方針はDjangoFilterConnectionField
を継承した独自のFilterConnectionを実装し、検索件数を制限すること。今回は1回のアクセスで最大1000件までとする。
models.py
from django.db import models
## 対象のモデル. なんでも大丈夫
class Tags(models.Model):
name = models.CharField(max_length=128, blank=True, null=True)
description = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tags'
schema.py
from graphene import Schema, ObjectType, Node
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField
from . import models
# connection_resolverをオーバーライドし最大件数を指定する
class LimitedDjangoFilterConnectionField(DjangoFilterConnectionField):
# 今回は一度に取得できる最大件数を1000とする
MAX_LIMIT = 1000
@classmethod
def connection_resolver(cls,
resolver,
connection,
default_manager,
max_limit, #1回で取得できる最大件数
enforce_first_or_last, #firstかlastが必要とするかどうか
filterset_class,
filtering_args,
root,
info,
**args):
return super(LimitedDjangoFilterConnectionField, cls).connection_resolver(
resolver,
connection,
default_manager,
MAX_LIMIT, #ここで1回に取得できる最大件数を指定
True, #ここでfirstかlastを必要とするように指定
filterset_class,
filtering_args,
root,
info,
**args)
class Tag(DjangoObjectType):
class Meta:
model = models.Tags
interfaces = (Node, )
filter_fields = {
"name": ["icontains"],
"description": ["icontains"]
}
class Query(ObjectType):
tag = Node.Field(Tag)
# 上で定義した独自クラスを使用
all_tags = LimitedDjangoFilterConnectionField(tag)
schema = Schema(query=Query)
クエリ例
下記クエリを投げるとエラーが返される。
# 指定件数が多すぎる場合
query {
allTags(first: 2000) {
edges {
node {
name
}
}
}
}
# 指定件数がない場合
query {
allTags(name_Icontains: "Py") {
edges {
node {
name
}
}
}
}