ゆーじぇいブログ

ゆーじぇいブログ

プログラミングとか色々

DjangoでAPI&Nuxtでいいね機能を実装

f:id:jyouj:20181124165447p:plain

以前、Djangoでいいね機能を実装したことがありましたが、今回Django Restful APIを使い、Nuxtの方でいいね機能を実装してみようと思います。

jyouj.hatenablog.com

DjangoAPIを作成

User APIはフォロー機能を実装した時のものを使おうと思います。こちらを参照ください。

jyouj.hatenablog.com

Postモデル&Likeモデルはすでにできていると仮定します。できていなければ、上の"Djangoでいいね機能"を参照してください。Serializerを作っていきましょう。

from posts.models import Post, Like

class PostMiniSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'text', 'background', 'date_created',]

class PostWriteSerializer(serializers.ModelSerializer):
    likes_count = serializers.SerializerMethodField()
    is_liking = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = ('id', 'background', 'text', 'date_created', 'likes_count', 'is_liking')

    def get_likes_count(self, obj):
        return obj.likes.count()

    def get_is_liking(self, obj):
        user = self.context['request'].user

        if user.is_authenticated:
            return Like.objects.filter(user=user, post=obj).exists()
        else:
            return False


class PostReadSerializer(PostWriteSerializer):
    user = UserMiniSerializer()

    class Meta(PostWriteSerializer.Meta):
        fields = PostWriteSerializer.Meta.fields + ('user',)

permissions.pyにも付け足しておきましょう。

class IsPosterOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True

        return obj.user == request.user

それではviewsetを書いていきましょう。

from django.db.models import Q

from django.shortcuts import render
from rest_framework import viewsets, filters, status, permissions, filters
from rest_framework.response import Response
from rest_framework.decorators import action

from users.models import User, Connection
from posts.models import Post, Like
from .serializers import (UserSerializer, UserMiniSerializer,
                          PostReadSerializer, PostWriteSerializer,)
from .permissions import IsMyselfOrReadOnly, IsPosterOrReadOnly

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsPosterOrReadOnly]
    filter_backends = [filters.SearchFilter]
    search_fields = ['text']

    def get_serializer_class(self):
        if self.request.method in ['POST', 'PUT', 'PATCH']:
            return PostWriteSerializer

        return PostReadSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

    @action(detail=True, permission_classes=[permissions.IsAuthenticated])
    def like(self, request, pk=None):
        obj, created = Like.objects.get_or_create(user=request.user, post=self.get_object())

        if created:
            return Response({'data': ['Like successfully']})
        else:
            return Response({'errors': ['You already like that post']}, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, permission_classes=[permissions.IsAuthenticated])
    def unlike(self, request, pk=None):
        if not Like.objects.filter(user=request.user, voice=self.get_object()).exists():
            return Response({'errors': {"You aren't like that post"}}, status=status.HTTP_400_BAD_REQUEST)

        Like.objects.get(user=request.user, post=self.get_object()).delete()

        return Response({'data': ['Unlike successfully']})

urls.pyにも付け加えておきましょう。

router.register('posts', PostViewSet)

Djangoでいいね機能を作った時と基本的には変わらない感じかなー、と思います。

Nuxt側の実装

Nuxt側でいいね機能を実装してみましょう。Componentに分割したり、FontAwesomeとか使っているんですが、あんま気にしないでください(笑)。適時、読み替えてください。

PostのレイアウトやPost APIを受け取るところは省略させてください。今回はいいね機能の受け渡し、ということで。

<action-icon v-if="post.is_liking" slot="icon" icon="heart" :num="post.likes_count" @click.native="unlike"/>
<action-icon v-else slot="icon" icon="heart" :num="post.likes_count" @click.native="like"/>

さて、scriptの方も書いていきましょう。

  props: {
    post: { required: true }
  },
  methods: {
    async like() {
      await this.$axios.get(`/api/posts/${this.post.id}/like/`)
      this.post.is_liking = true
      this.post.likes_count++
    },
    async unlike() {
      await this.$axios.get(`/api/posts/${this.post.id}/unlike/`)
      this.post.is_liking = false
      this.post.likes_count--
    }
  }

ログインしておけばこれで色々動くと思います。いいね機能付け加えたい時、参考にしてください。PostのAPIの受け渡しに関してはおそらく色々と記事があるのでそれを参考にしてみてください。

何かあれば、じぇい👨‍💻 (@jyouj__) | Twitterに!