🍣
[DRF]RetrieveAPIViewがgetリクエストされて、オブジェクトを一意に特定するまでの流れ
書くこと
- RetrieveAPIViewがgetリクエストされて、オブジェクトを一意に特定するまでの流れ
- queryset, get_queryset, get_objectsの内部挙動
利用する技術
- Django REST Framework
- rest_framework.generics
想定シチュエーション
以下のようなRetrieveAPIViewがあるとする。
class ArticleView(RetrieveAPIView):
"""Articleの参照APIクラス"""
queryset = Article.objects.all()
# 以下をオーバーライドしない想定
# def get_queryset(self):
# def get_object(self):
集合の絞り込み観点
def get_object(self):
⊂ def get_queryset(self):
⊂ queryset = Article.objects.all()
参照/呼び出し順序
def get_object(self):
def get_queryset(self):
queryset = Article.objects.all()
内部コードを知る
1.RetrieveAPIView#get
class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView):
"""
Concrete view for retrieving, updating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
2.RetrieveModelMixin#retrieve
class RetrieveModelMixin:
def retrieve(self, request, *args, **kwargs):
# 呼び出し1: get_object()
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
3. GenericAPIView#get_object
class GenericAPIView(views.APIView):
def get_object(self):
# 呼び出し2: get_queryset()
queryset = self.filter_queryset(self.get_queryset())
# Perform the lookup filtering.
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
assert lookup_url_kwarg in self.kwargs, (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwarg)
)
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
4. GenericAPIView#get_queryset
class GenericAPIView(views.APIView):
def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
# 呼び出し3(参照): self.queryset
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
Discussion