【DRF】複数の検索キーを使って目的のレコードを取得する方法
Django Rest Frameworkで複数の検索キーを使って1つのレコードの取得/更新/削除をしたい
PythonのREST APIフレームワークであるDjango REST Framework(DRF)を使うときに目的の単一レコードを操作するときの小ワザです。
DRFについてはある程度知識があることが前提。
🚀 DRFについてはこちらに概要を説明した記事があるので参照
Django REST Frameworkを使って爆速でAPIを実装する
Django REST framework カスタマイズ方法 - チュートリアルの補足
[Django REST Framework] View の使い方をまとめてみた
単一の検索キーでレコードを操作したい場合
汎用API ViewなどのViewに関わるクラスにはlookup_field
というクラス変数が設定されているので、これを利用する。RetrieveAPIView
(取得)やUpdateAPIView
(更新)、DeleteAPIView
(削除)などで単一のインスタンス(=レコード)を操作するときに使用される。
デフォルトではpk
(プライマリーキー)が割り当てられているので、継承して使う場合は明記する必要はない。
例えば、Country
というモデルがあった時に、id = 1
(us)のレコードを取得したい場合は、下のようなViewクラスを書いて、urls.py
の~coutries/1/
というエンドポイントにGETメソッド経由でHTTPリクエストを送れば取得できる。
ちなみに検索キーをpk
から他のフィールド(例えばname
)に変更したい場合はlookup_field = 'name'
のように書けばいい。
urlpatterns = [
path('coutries/<int:pk>/', name='detail_country')
]
from rest_framework import generics
class CountryRetrieveAPIView(generics.RetrieveAPIView):
queryset = Country.objects.all()
serializer_class = CountrySerializer
# デフォルトでpk(id)が設定されているので、pkを指定する場合は書かなくてもいい
lookup_field = 'pk'
複数の検索キーでレコードを操作したい場合
しかし、次のようにエンドポイントに複数のキーが入っている場合がある。
例えば、外部参照キーcountry=1(us)
のStateというテーブルからid=6(カリフォルニア州)
のレコードを取得したい場合。
urlpatterns = [
# `country`と`pk`の2つのキーを使って単一レコードを取得したい
path('coutries/<int:country>/states/<int:pk>/', name='detail_state')
]
こんな場合は上のviews.py
のままではうまくいかない。
汎用APIViewには目的のクエリセットを返すget_queryset()
というメソッドが用意されているので、これをオーバーライドして、ORMで抽出条件を調整すればよいが、面倒に感じる場合はDRF公式ドキュメントに載っている次のMixinクラスを利用すると簡単に目的のクエリセットを取得できるのでおすすめ。
class MultipleFieldLookupMixin(object):
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
このMixinを多重継承して利用する。
これでlookup_field
(単数形)の代わりにlookup_fields
(複数形)が使えるようになるので、タプルかリストで値をセットすればOK。
これで~coutries/1/states/6/
にGETリクエストを送るとアメリカ合衆国(country_id=1
)かつカリフォルニア州(id=6
)のレコードを取得できる。
from django.shortcuts import get_object_or_404
from rest_framework import generics
# MultipleFieldLookupMixinを多重継承して使う
class StateRetrieveAPIView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = State.objects.all()
serializer_class = StateSerializer
# エンドポイントに含まれる複数の検索キーを指定できる
lookup_fields = ('country', 'pk')
さらに次のようにして多重継承しただけのクラスを作って、他モジュールからインポートして使うようにカスタマイズもできる。
from django.shortcuts import get_object_or_404
from rest_framework import generics
class MultipleFieldLookupMixin(object):
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
# インポートして使える
class BaseRetrieveAPIView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
pass
# インポートして使える
class BaseRetrieveUpdateDestroyAPIView(MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPIView):
pass
Author And Source
この問題について(【DRF】複数の検索キーを使って目的のレコードを取得する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/_masa_u/items/5ff1a3313e0bd94f162a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .