Django投稿&いいですね&follow


Westagramプロジェクトを行い、初期設定からログイン機能まで実現しました.ここでは、追加のタスク投稿、コメント、良いfollow機能を実現することで、Django APIの作成をより熟知しています.

Model


Djangoでは、主に処理するデータの種類が異なる場合にアプリケーションを分離することが望ましい.したがって、postingsというアプリケーションが新しく作成され、新しいテーブル間でモデリングされ、ERDが作成されます.
ERDは以下を含む.
モデリングのERDに基づいてモデルを作成した.
# posings/models.py

from django.db import models

class Posting(models.Model):
    image_url  = models.URLField()
    content    = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    user       = models.ForeignKey('users.User', on_delete=models.CASCADE)

    class Meta:
        db_table = 'postings'

class Comment(models.Model):
    user       = models.ForeignKey('users.User', on_delete=models.CASCADE)
    posting    = models.ForeignKey('Posting', on_delete=models.CASCADE)
    content    = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'comments'

class Like(models.Model):
    user    = models.ForeignKey('users.User', on_delete=models.CASCADE)
    posting = models.ForeignKey('Posting', on_delete=models.CASCADE)

    class Meta:
        db_table = 'likes'
Postings appがユーザー・アプリケーションのユーザー・カテゴリとしてForeignKeyを使用している場合、参照するテーブルの名前はAppNameです.正しく適用するには、Table Nameとして指定します.
# users/models.py

from django.db import models

class User(models.Model):
    name         = models.CharField(max_length=30)
    email        = models.EmailField(max_length=50, unique=True)
    password     = models.CharField(max_length=120)
    phone_number = models.CharField(max_length=20)
    created_at   = models.DateTimeField(auto_now_add=True)
    updated_at   = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'users'

class Follow(models.Model):
    follow   = models.ForeignKey('User', on_delete=models.CASCADE, related_name='follow')
    followed = models.ForeignKey('User', on_delete=models.CASCADE, related_name='followed')

    class Meta:
        db_table = 'follows'
followとfollowはユーザ間で発生する機能であるためusers appで作成される.
ERDでは、2つのForeignKeyが1つのクラスで同じオブジェクトを参照し、関連するnameを使用しない場合、次のエラーが発生します.

Followクラスではfollow、follow Fieldが同じUserクラスオブジェクトを参照するため、この2つのインスタンスを指定しないと区別できません.
したがって、Userクラスオブジェクトを参照するフィールドはrelated nameで区切らなければなりません.

Posting View

class PostingView(View):
    def post(self, request):
        try:
            data      = json.loads(request.body)
            image_url = data['image_url']
            content   = data['content']
            user      = User.objects.get(email=data['email'])

            if not User.objects.filter(email=data['email']).exists():
                return JsonResponse({'message':'INVALID_USER'}, status=401)

            Posting.objects.create(
                image_url = image_url,
                content   = content,
                user      = user
            )

            return JsonResponse({'message':'SUCCESS'}, status=201)

        except KeyError:
            return JsonResponse({'message':'KEY_ERROR'}, status=400)

    def get(self, request, posting_id):
        if not Posting.objects.filter(id=posting_id).exists():
            return JsonResponse({'message':'NON_POST'}, status=400)

        posting  = Posting.objects.get(id=posting_id)
      
        results  = []
        results.append(
            {
                'user'       : posting.user.email,
                'image_url'  : posting.image_url,
                'content'    : posting.content,
                'created_at' : posting.created_at
            }
        )

        return JsonResponse({'results':results}, status=200)
# postings/urls.py

urlpatterns = [
    path('/posting', PostingView.as_view()),
    path('/posting/<int:posting_id>', PostingView.as_view()),
]    
特定の投稿の情報のみを取得するためにurls.pyには整数型idを参照するコードが追加されています.また,GETメソッドにpost idパラメータを追加する.これでpost/1はID 1の投稿をロードできます.
http -v POST 127.0.0.1:8000/postings/posting email='r123@gma
il.com' image_url='https://cdn.pixabay.com/photo/2022/01/29/11/02/cat-6977096_1280.jpg' content='고양이 사진'
http -v GET 127.0.0.1:8000/postings/posting/2

Comment View

class CommentView(View):
    def post(self, request):
        try:
            data       = json.loads(request.body)
            content    = data['content']
            user       = User.objects.get(email=data['email'])
            
            if not User.objects.filter(email=data['email']).exists():
                return JsonResponse({'message':'INVALID_USER'}, status=401)

            if not Posting.objects.filter(id=data['posting_id']).exists():
                return JsonResponse({'message':'NON_POST'}, status=401)

            Comment.objects.create(
                user       = user,
                posting_id = data['posting_id'],
                content    = content
            )

            return JsonResponse({'message':'SUCCESS'}, status=201)

        except KeyError:
            return JsonResponse({'message':'KEY_ERROR'}, status=400)

    def get(self, request, posting_id):
        comments = Comment.objects.filter(posting_id=posting_id)

        results = [{
            'user'       : comment.user.email,
            'content'    : comment.content,
            'created_at' : comment.created_at
        } for comment in comments]

        return JsonResponse({'reuslts':results}, status=200)
urlpatterns = [
    path('/posting', PostingView.as_view()),
    path('/posting/<int:posting_id>', PostingView.as_view()),
    path('/comment', CommentView.as_view()),
    path('/<int:posting_id>/comment', CommentView.as_view()),
]    
PostingViewのように特定の投稿に関するコメント、URLのみを取得するために.pyに整数型idを参照するコードを追加し、パラメータも追加しました.
 http -v POST 127.0.0.1:8000/postings/comment email='[email protected]' content='귀여운 고양이네요' posting_id=2
http -v GET 127.0.0.1:8000/postings/2/comment

Like View & Follow View

class LikeView(View):
    def post(self, request):
        try: 
            data = json.loads(request.body)
            user = User.objects.get(email=data['email'])

            if not User.objects.filter(email=data['email']).exists():
                return JsonResponse({'message':'INVALID_USER'}, status=401)

            if not Posting.objects.filter(id=data['posting_id']).exists():
                return JsonResponse({'message':'NON_POST'}, status=401)

            like = Like.objects.filter(user=user, posting_id=data['posting_id'])

            if like.exists():
                like.delete()
                return JsonResponse({'message':'LIKE_DELETE'}, status=200)

            Like.objects.create(
                user       = user,
                posting_id = data['posting_id']
            )

            # like, is_like = Like.objects.get_or_create(
            #     user       = user,
            #     posting_id = data['posting_id']
            # )

            # if not is_like:
            #     like.delete()
            #     return JsonResponse({"message":"LIKE_DELETE"}, status=200)

            return JsonResponse({'message':'SUCCESS'}, status=201)

        except KeyError:
            return JsonResponse({'message':'KEY_ERROR'}, status=400)

class FollowView(View):
    def post(self, request):
        try:
            data        = json.loads(request.body)
            follow_id   = data['follow_id']
            followed_id = data['followed_id']
            
            if not User.objects.filter(id=follow_id).exists():
                return JsonResponse({'message':'INVALID_USER'}, status=401)
            
            if not User.objects.filter(id=followed_id).exists():
                return JsonResponse({'message':'INVALID_USER'}, status=401)


            follow = Follow.objects.filter(follow_id=follow_id, followed_id=followed_id)

            if follow.exists():
                follow.delete()
                return JsonResponse({'message':'UNFOLLOWED'}, status=200)

            Follow.objects.create(
                follow_id   = follow_id,
                followed_id = followed_id
            )

            # follow, is_follow = Follow.objects.get_or_create(
            #     follow   = User.objects.get(email=data['follow']),
            #     followed = User.objects.get(email=data['followed'])
            # )

            # if not is_follow:
            #     follow.delete()
            #     return JsonResponse({"MESSAGE":"UNFOLLOWED"}, status=200)

            return JsonResponse({'message':'FOLLOWED'}, status=201)

        except KeyError:
            return JsonResponse({'message':'KEY_ERROR'}, status=400)
http -v POST 127.0.0.1:8000/postings/like email='[email protected]' posting_id=2
 http -v POST 127.0.0.1:8000/postings/follow follow_id=5 followed_id=4

すでに点賛と注目を集めている場合、同じ要求を出すと、点賛が解除され、注目されないことが実現します.
従来の基数がget or createメソッドで実現されているのを見ると,確かにコードが簡潔になるにつれてcreate,delete機能を同時に処理できるのは良い方法である.