본인이기 때문에 'self'
입력해야 한다.
symmetrical
은 본인self일 때 해야 하는 특징적인 옵션으로
symmetrical=False
는 일방적인 Follow를 의미한다. 예: Instagram
# user/models.py
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
# 추가
followings = models.ManyToManyField('self', symmetrical=False, related_name='followers')
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
makemigrations
migrate
url을 설계한다.
# users/urls.py
from django.urls import path, include
from users import views
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('signup/', views.UserView.as_view(), name='user_view'),
path('mock/', views.mockView.as_view(), name='mock_view'),
path('api/token/', views.CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('follow/<int:user_id>/', views.FollowView.as_view(), name="follow_view"), # 추가
]
urls을 만들었으니
views.py에서 FollowView
만들어야 한다.
# users/views.py
from rest_framework.views import APIView
from rest_framework.generics import get_object_or_404
from rest_framework import status, permissions
from rest_framework.response import Response
from rest_framework_simplejwt.views import (
TokenObtainPairView
)
from users.models import User
from users.serializers import CustomTokenObtainPairSerializer, UserSerializer
class UserView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"message":"회원가입이 완료되었습니다."})
else:
return Response({"message":f"${serializer.errors}"}, status=status.HTTP_400_BAD_REQUEST)
class FollowView(APIView): # 좋아요와 비슷한 로직. 토글 형식.
def post(self, request, user_id):
# user가 2가지 있어서 혼동 방지를 위해
you = get_object_or_404(User, id=user_id)
me = request.user
if me in you.followers.all(): # users/models.py의 related_name=followers
you.followers.remove(me) # (request.user)
return Response("언팔로우 했습니다.", status=status.HTTP_200_OK)
else:
you.followers.add(me) # 너의 팔로워에 나를 더해라
return Response("팔로우 했습니다.", status=status.HTTP_200_OK)
Send
를 다시 한 번 누르면 팔로우가 취소된다.
DB에서도 관련 폴더가 생겨 팔로우 현황이 확인된다.