上記の記事の続きです。
今回はQuerySetで用意されているAPIを動作確認してみたいと思います。
https://docs.djangoproject.com/en/4.1/ref/models/querysets/
先にデータを用意したいので以下のloop.shスクリプトを作成しました。
#!/bin/bash for i in `seq 1 20`; do echo $i username="testuser$i" age="$i" echo $username echo $age curl -X POST -H "Content-Type: application/json" -d "{\"name\":\"$username\", \"age\":$age}" http://localhost:8000/blog/user_viewset/ done
sh script/loop.sh
で実行するとユーザーのデータを作成することができました。
sh script/list.sh [{"id":5,"name":"testuser1","age":1},{"id":6,"name":"testuser2","age":2},{"id":7,"name":"testuser3","age":3},{"id":8,"name":"testuser4","age":4},{"id":9,"name":"testuser5","age":5},{"id":10,"name":"testuser6","age":6},{"id":11,"name":"testuser7","age":7},{"id":12,"name":"testuser8","age":8},{"id":13,"name":"testuser9","age":9},{"id":14,"name":"testuser10","age":10},{"id":15,"name":"testuser11","age":11},{"id":16,"name":"testuser12","age":12},{"id":17,"name":"testuser13","age":13},{"id":18,"name":"testuser14","age":14},{"id":19,"name":"testuser15","age":15},{"id":20,"name":"testuser16","age":16},{"id":21,"name":"testuser17","age":17},{"id":22,"name":"testuser18","age":18},{"id":23,"name":"testuser19","age":19},{"id":24,"name":"testuser20","age":20}]
これまでにidを指定した1件のデータ取得の動作確認を行なっていなかったのでスクリプトを追加してみます。
touch script/retrieve.sh
retrieve.shは以下の内容にします。
#!/bin/bash if [ $# -eq 0 ]; then echo "please specify id." exit 1 fi curl -H "Content-Type: application/json" http://localhost:8000/blog/user_viewset/$1/
以下のようにデータが取得できました。
sh script/retrieve.sh 5 {"id":5,"name":"testuser1","age":1}
更新処理も確認するためのスクリプトを作成します。
touch script/update.sh
update.shは以下のようにしました。
#!/bin/bash if [ $# -eq 0 ]; then echo "please specify id." exit 1 fi curl -X PUT -H "Content-Type: application/json" -d '{"name":"testuser1updated", "age":"100"}' http://localhost:8000/blog/user_viewset/$1/
id5のtestuser1でupdate処理ができることを確認しました。
sh script/update.sh 5 {"id":5,"name":"testuser1updated","age":100} sh script/retrieve.sh 5 {"id":5,"name":"testuser1updated","age":100}
次にQuerySetをフィルタリングできるか確認してみます。
Django REST Frameworkでは公式ドキュメントは下記だと思います。 https://www.django-rest-framework.org/api-guide/filtering/
The default behavior of REST framework's generic list views is to return the entire queryset for a model manager. Often you will want your API to restrict the items that are returned by the queryset.
REST frameworkのgeneric list viewのデフォルトの挙動はmodel managerの全体のquerysetを返すことだが、返される値を制御したい場合もあるでしょう、的な感じに解釈しました。
The simplest way to filter the queryset of any view that subclasses GenericAPIView is to override the .get_queryset() method.
Overriding this method allows you to customize the queryset returned by the view in a number of different ways.
GenericAPIViewのサブクラスのquerysetをフィルタリングするシンプルな方法はget_queryset()メソッドをoverrideすることです。このメソッドをorverrideすることでviewが返すquerysetをカスタマイズできます、的な感じに解釈しました。
ドキュメントに書かれているquery parameterを使ってフィルタリングするためのサンプルコードは下記です。
https://www.django-rest-framework.org/api-guide/filtering/#filtering-against-query-parameters
class PurchaseList(generics.ListAPIView): serializer_class = PurchaseSerializer def get_queryset(self): """ Optionally restricts the returned purchases to a given user, by filtering against a `username` query parameter in the URL. """ queryset = Purchase.objects.all() username = self.request.query_params.get('username') if username is not None: queryset = queryset.filter(purchaser__username=username) return queryset
まずは真似してコードを書いてみます。 フィルタリングする処理を書くためのファイルを新規に作成しました。
touch drfproject/blog/filter_view.py
filter_view.pyを以下のようにしました。
from .models import User from .serializers import UserSerializer from rest_framework import generics class FilteredUsersList(generics.ListAPIView): serializer_class = UserSerializer def get_queryset(self): queryset = User.objects.all() username = self.request.query_params.get('name') if username is not None: queryset = queryset.filter(name=username) return queryset
上記コードを書く際、以下の画像のようにVSCodeで補完が動作していました。
drfproject/blog/urls.pyは以下のように編集しサーバーを起動することができました。 FilteredUsersListはgenerics.ListAPIViewを継承しているのでas_view()でpath()に渡すことができるみたいです。
from django.urls import path, include from blog import views from .viewsets import UserViewSet from .filter_view import FilteredUsersList from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r'user_viewset', UserViewSet, basename='user_viewset') urlpatterns = [ path('', include(router.urls)), path('users_list', views.users_list), path('filter_view', FilteredUsersList.as_view()) ]
filter_viewにリクエストを送るためのスクリプトを作成します。
touch script/filter_view.sh
filter_view.shは以下のようにしました。
#!/bin/bash if [ $# -eq 0 ]; then echo "please specify name." exit 1 fi curl -H "Content-Type: application/json" http://localhost:8000/blog/filter_view?name=$1
以下のようにフィルタリングされたQuerySetが返ってくることが確認できました。
sh ../script/filter_view.sh testuser 3 [{"id":7,"name":"testuser3","age":3}]
filter以外にもいろいろQuerySetのAPIがあるようです。 https://docs.djangoproject.com/en/4.1/ref/models/querysets/#annotate
試しにexclude()を使ってみます。 https://docs.djangoproject.com/en/4.1/ref/models/querysets/#exclude
filter_view.pyを以下のように編集しました。
from .models import User from .serializers import UserSerializer from rest_framework import generics class FilteredUsersList(generics.ListAPIView): serializer_class = UserSerializer def get_queryset(self): queryset = User.objects.all() username = self.request.query_params.get('name') if username is not None: queryset = queryset.exclude(name=username) return queryset
再度リクエストを投げるとnameがtestuser3以外のものが取得できることが確認できました。
sh ../script/filter_view.sh testuser3 [{"id":5,"name":"testuser1updated","age":100},{"id":6,"name":"testuser2","age":2},{"id":8,"name":"testuser4","age":4},{"id":9,"name":"testuser5","age":5},{"id":10,"name":"testuser6","age":6},{"id":11,"name":"testuser7","age":7},{"id":12,"name":"testuser8","age":8},{"id":13,"name":"testuser9","age":9},{"id":14,"name":"testuser10","age":10},{"id":15,"name":"testuser11","age":11},{"id":16,"name":"testuser12","age":12},{"id":17,"name":"testuser13","age":13},{"id":18,"name":"testuser14","age":14},{"id":19,"name":"testuser15","age":15},{"id":20,"name":"testuser16","age":16},{"id":21,"name":"testuser17","age":17},{"id":22,"name":"testuser18","age":18},{"id":23,"name":"testuser19","age":19},{"id":24,"name":"testuser20","age":20}]