外部APIのデータをお気に入りしていく機能を実装したいと思います。
一応実装できたかなというくらいで、もっと良い書き方があるかもしれませんが、そこは勉強中なのでご容赦ください。。。
前回書いた記事同様、Finaicial Modeling Prepを使用していきます。
【Django REST Framework】外部APIをAPIViewで取得する
##1.モデルの作成
from django.conf import settings
class FavoStock(TimeStampModel):
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='favorites')
symbol = models.CharField(max_length=20, blank=False)
isin = models.CharField(max_length=12, blank=True)
vender = models.CharField(max_length=10, blank=True)
description = models.CharField(max_length=100, blank=False)
def __str__(self):
return f"{self.profile.user.username} likes {self.symbol}"
本来のお気に入り機能であれば、ForeignKeyFieldやManyToManyFieldで対象のモデルと接続するんでしょうが、今回はデータベースに銘柄リストを登録していないため、普通の登録・削除の機能に近いです。
##2.シリアライザの作成
from rest_framework import serializers
from profiles.models import Profile, FavoStock
class FavoStockSerializer(serializers.ModelSerializer):
profile = serializers.StringRelatedField(read_only=True)
class Meta:
model = FavoStock
exclude = ('updated_at', )
#3.ビューの作成
class FavoStockListAPIView(mixins.ListModelMixin,
generics.GenericAPIView):
serializer_class = FavoStockSerializer
permission_classes = [IsAuthenticated, ]
def get_queryset(self):
queryset = FavoStock.objects.all()
request_uuid = self.kwargs.get('uuid')
return queryset.filter(profile__uuid=request_uuid).order_by('-created_at')
def get(self, request, uuid):
return self.list(request)
class FavoStockCreateAPIView(generics.CreateAPIView):
queryset = FavoStock.objects.all()
serializer_class = FavoStockSerializer
permission_classes = [IsAuthenticated, IsOwnFavoStockOrReadOnly]
def perform_create(self, serializer):
symbol = self.request.data.get('symbol')
user_profile = self.request.user.profile
queryset = self.get_queryset()
has_user_added = self.queryset.filter(symbol=symbol, profile=user_profile).exists()
if has_user_added:
raise ValidationError('already added.')
serializer.save(profile=user_profile)
class FavoStockDestroyAPIView(generics.DestroyAPIView):
queryset = FavoStock.objects.all()
serializer_class = FavoStockSerializer
permission_classes = [IsAuthenticated, IsOwnFavoStockOrReadOnly]
lookup_field ='symbol'
def perform_destroy(self, instance):
symbol = self.kwargs.get('symbol')
user_profile = self.request.user.profile
queryset = self.get_queryset()
has_user_added = self.queryset.filter(symbol=symbol, profile=user_profile).exists()
if not has_user_added:
raise ValidationError('not exists.')
instance.delete()
ここはもう少し短くできるだろうなとモヤモヤしています。
ListViewではプロファイルのuuidをパラメータとして渡すことで、そこ人のお気に入り一覧を見ることができます。
Create、Destroyでは自分が登録したレコード以外は操作できないようにしています。
重複などを避けるためにhas_user_addedでレコードのチェックを行っています。
##4.URLの設定
path('addfavorite/', FavoStockCreateAPIView.as_view(), name="add-favorite"),
path('removefavorite/<str:symbol>/', FavoStockDestroyAPIView.as_view(), name='remove-favorite'),
上記をurlpatternsに追加しました。
##(メモ:permissions.py)
class IsOwnFavoStockOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.profile == request.user.profile
##まとめ
とりあえず実装できました。
FavoStockモデルはProfileアプリの中にある一方で、株式の情報取得は別のアプリで行っているなど、まだまだ理解ができていないところが多いですが、少しづつ勉強していきます。
(なんでFavoStockって中途半端な名前にしたんだろう…)