🐙
[DRF]エンドポイントに含まれる複合ユニークキーを利用して単一レコードを取得する
書くこと
- DRFのViewに標準搭載されている
lookup_field
に似た機能として、lookup_fields
を実現するmixinの実装-
lookup_field
は単一キーによるレコード取得(<--標準搭載) -
lookup_fields
では複数キーによるレコード取得(<--実現する!)
-
- mixinを利用したViewファイルの記述例
利用する技術
- Django REST Framework
- rest_framework.generics
想定シチュエーション
複合ユニークキーが含まれていて、この複合ユニークキーを使ったレコード取得をしたい。
urlpatterns = [
# user_idとpkによる複合ユニークキー
path('user/<user_id>/post/<pk>/', PostDetailView.as_view())
# example:
# 'user/1/post/1/', PostDetailView.as_view())
# => User<id:1>の最初の投稿を取得する
]
方法論
MultipleFieldLookupMixinを定義する
公式から例として提供されている
common/multiple_field_lookup_mixin.py/
class MultipleFieldLookupMixin:
def get_object(self):
queryset = self.get_queryset()
queryset = self.filter_queryset(queryset)
filter = {}
for field in self.lookup_fields:
if self.kwargs.get(field):
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter)
self.check_object_permissions(self.request, obj)
return obj
Viewを定義する
view/post_details.py/
from ..common.multiple_field_lookup_mixin import MultipleFieldLookupMixin
# 単一レコードへの操作系Viewで利用する
# Retrieve, Update, Destroy
from rest_framework.generics import RetrieveUpdateDestroyAPIView
class PostDetailView(MultipleFieldLookupMixin, RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
# (省略)serializer_class = SomethingSerializer
lookup_fields = ('user_id', 'pk')
# get_objectで書く手間を省ける
# def get_object(self):
# user_id = self.kwargs.get("user_id")
# pk = self.kwargs.get("pk")
# etc....
付録: エンドポイント含まれるユニークキーで単一レコードを取得する
想定シチュエーション
ユニークキーが含まれていて、このユニークキーを使ったレコード取得をしたい。
urlpatterns = [
# user_idとpkによる複合ユニークキー
path('post/<post_id>/', PostDetailView.as_view())
Viewを定義する
view / post_details.py /
# 単一レコードへの操作系Viewで利用する
# Retrieve, Update, Destroy
from rest_framework.generics import RetrieveUpdateDestroyAPIView
class PostDetailView(RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
# (省略)serializer_class = SomethingSerializer
# lookup_fieldはDRFが標準提供している
lookup_field = 'post_id'
# lookup_field値は'pk'なので今回の例では、以下の`url_patterns`にすることで省略可
# path('post/<pk>/', PostDetailView.as_view())
Discussion