前回までの記事
1.Django REST framework + Vue.js「SEIYU風のECサイトを作りましょう」全6回(予定)
2.SEIYU風のECサイトを作りましょう(1)要求分析とプロジェクト初期化
3.SEIYU風のECサイトを作りましょう(2)Xadminを使って管理画面を一新します
前書き
今回の記事はDjango REST frameworkを使用して、APIを作っていきます。
テスト用のデータが必要なため、**商品(goods)とカテゴリ(GoodsCategory)**のデータを予め用意します。
管理画面から手入力でもできますが、本記事のリポジトリにあるdb_tools
フォルダをコピーして使用することをオススメします。
本記事リポジトリ
使い方
qiita-Django-supermarket/api/db_tools/
配下にある、以下の二つのファイルを実行して下さい。
そうすればテストデータがDBに追加されます。
import_category_data.py
import_goods_data.py
商品(goods)API
まずはSerializersを作ります。
Djangoのformsとして考えていいです。
cd apps/goods
vim serializer.py
from rest_framework import serializers
from .models import Goods
class GoodsSerializer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = "__all__"
次はgoodsのviews.pyを編集します。
from rest_framework import mixins
from rest_framework import viewsets
from .models import Goods
from .serializer import GoodsSerializer
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
最後はurls.pyに以下を追加します。
...
from django.urls import path, re_path, include
from rest_framework.routers import DefaultRouter
from goods.views import GoodsListViewSet
...
router = DefaultRouter()
router.register(r'goods', GoodsListViewSet)
...
urlpatterns = [
...
re_path('^', include(router.urls)),
...
]
以上の三点を追加すれば、商品リストのAPIは出来上がりです。
以下コマンドを実行し、サーバーを再起動します。
python manage.py runserver
http://127.0.0.1:8000/
にアクセスし、正しくデータが取得できたことを確認します。
データあるだけではAPIとして不親切なので、オプションをつけていきます。
ページング
Django REST frameworkにページングを追加する方法は以下の二つがあります。
- setting.pyにグローバル配置する
- 各views.pyにローカルなページングを追加する
今回はローカルに追加する方法を使用します。
goodsのviews.pyに以下を追加します。
...
from rest_framework.pagination import PageNumberPagination
...
class GoodsSetPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 100
...
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
....
pagination_class = GoodsSetPagination
以上の内容追加後、再度http://127.0.0.1:8000/goods/
にアクセスします。
ページングが確認できたらオーケーです。
フィルタ
商品に関するフィルタ、よくあるのは以下の3つです。
- 値段順に並び替え
- 値段区間内検索
- キーワード検索
それら全部フロントでやれますが、勉強のため、バックエンドで実装します。
先ずはsettings.pyに以下を追加します。
INSTALLED_APPS = [
...
'django_filters'
]
次はviews.pyに以下を追加します。
...
from django_filters.rest_framework import DjangoFilterBackend
...
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
...
filter_backends = (DjangoFilterBackend,)
filterset_fields = ('name', 'shop_price')
...
以上の二点完成後、http://127.0.0.1:8000/goods/
にアクセスします。
フィルタという項目が追加されたことが確認できます。
商品名を入力すれば、フィルタが機能してることが確認できます
今のフィルタは商品名が完全一致でなければ表示されません。
親切とは言えませんので、もう少し工夫して部分一致を可能にします。
goodsの配下にfilters.pyファイルを作ります。
import django_filters
from .models import Goods
class GoodsFilter(django_filters.rest_framework.FilterSet):
"""
goodsのfilter
"""
price_min = django_filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
class Meta:
model = Goods
fields = ['price_min', 'price_max']
views.pyに追加とコメントアウトを行います。
...
from rest_framework import filters
from .filters import GoodsFilter
...
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
...
# filterset_fields = ('name', 'shop_price')
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
filterset_class = GoodsFilter
search_fields = ['name', 'goods_brief']
ordering_fields = ['shop_price']
http://127.0.0.1:8000/goods/
にアクセスします。
- 値段順に並び替え
- 値段区間内検索
- キーワード検索
以上3つの商品に関するフィルタが完成しました。
外部キーの処理
Goodsモデルにはcategoryという外部キーが存在します。
今のAPIでは数字のIDとして表示してますが、参照先の詳細を表示できるようにしましょう。
goodsのserializer.pyを修正します。
...
from .models import GoodsCategory
...
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = "__all__"
...
class GoodsSerializer(serializers.ModelSerializer):
category = CategorySerializer()
...
修正後、カテゴリの詳細も表示できるようになりました。
カテゴリ(category )API
カテゴリの内容は商品ほど多くはないですが、自身を外部キーとして扱うカテゴリの階級が存在します。
それを実装しましょう。
class CategorySerializer3(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = "__all__"
class CategorySerializer2(serializers.ModelSerializer):
sub_cat = CategorySerializer3(many=True)
class Meta:
model = GoodsCategory
fields = "__all__"
class CategorySerializer(serializers.ModelSerializer):
sub_cat = CategorySerializer2(many=True)
...
次はviews.pyに以下を追加します。
...
from .models import GoodsCategory
from .serializer import CategorySerializer
...
class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = GoodsCategory.objects.filter(category_type=1)
serializer_class = CategorySerializer
urls.pyに以下を追加します。
...
from goods.views import CategoryViewSet
...
router.register(r'categorys', CategoryViewSet, base_name="categorys")
...
以上の修正できたら、http://127.0.0.1:8000/
にアクセスして確認します。
階層分けされたデータが確認できるはずです。
以上でカテゴリAPIが完成です。
APIドキュメント
もしバックエンドとフロントエンドを二人で担当する場合。
フロントエンドエンジニアが作業をしやすくするために、
バックエンドエンジニアはAPIのドキュメントを作る必要があります。
Django REST frameworkにはドキュメント自動生成する機能は備えてあります。
それを機能を有効化しましょう。
setting.pyに以下を追加します。
...
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema'
}
...
ドキュメント用のルートを追加します。
urls.pyに以下を追加します。
...
from rest_framework.documentation import include_docs_urls
...
urlpatterns = [
...
path('docs/', include_docs_urls(title="shop")),
]
http://127.0.0.1:8000/docs/
にアクセスし、ドキュメントの画面を確認します。
以下のように空白のカラムがある場合には、ヘルプテキストを追加する必要があります。
空白のカラムにhelp_textを追加してください。
price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte', help_text="最大額")
以上、APIの制作は一旦完了です。
新規登録、ログインなどのAPIはVue.jsプロジェクトの制作と共に作っていきます。
最後まで読んで頂きありがとうございます。
#次回予告
Vue.jsプロジェクトの初期化