Follow기능 구현 // django 인스타그램 api(2)

2022. 4. 24. 22:54
  • django 인스타그램 api 시리즈​
  • json통신을 상정한 인스타그램의 백엔드적 기능을 구현
    • follow기능 구현
    • 자신을 참조하는 many to many field가 사용됨

 

Modeling

  • 기존에 만들었던(바로 그전 포스팅에서) 만들었던 User모델에 Follow를 위한 manytomanyfield 추가
  • 유저들은 서로서로에게 follow할 수 있으며, 한 유저가 다른 유저를 follow한다고 해서, follow된 유저가 follow한 유저를 following하게 되지는 않는다.
    • 따라서 user모델인 자기자신을 참조하며, 관계가 비대칭적이므로 대칭성(symetrical)=Flase 설정
  • 또한 M to M 필드는 원래 자동적으로 MtoM관계를 설명하기 위한 중간table이 자동 생성된다.
    • 그러나 through라는 속성에 특정 모델의 이름을 줌으로써, 중간 table을 직접만들어서 관리할 수 있음.
    • 아래 예시에서는 Follow라는 중간테이블을 의미하는 모델을 생성
  • 중간 테이블은 반드시 참조하게 되는 모델들의 pk를 Fk로 받는다.(즉 FK가 두개임)
    • 이때 related_name을 설정함으로써 관계를 맺은 테이블에 접근할 수 있음
    • 그러나 아래의 Follow모델처럼 자기자신을 참조하는 MtoM의 중간테이블의 경우, related_name을 반드시 설정해줘야 한다. 그렇지 않으면 related_name이 default로 정해진 값으로 설정되어 충돌이 발생함(즉 에러가 남)
  • 추가)다 만들고 나서 든 생각인데, Follow 중간테이블에 type이라는 필드를 추가해서, follow 또는 Block(차단)기능을 추가해볼 수도 있을 듯 함
    • 어차피 'Follow'와  'Block'을 동시에 할 수는 없으니까, Follow테이블을 그냥 relation같은 걸로 바꾸고 해당 테이블에 relation type같은 걸 추가해서 'follow'나 'block'을 함께 표시할 수 있을 듯함
#users : models.py
class User(TimeStampModel):
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=50,unique=True)
    password = models.CharField(max_length=200)
    phone_number = models.CharField(max_length=20)
    follow = models.ManyToManyField('self',through='Follow',symmetrical=False)

    class Meta:
        db_table='users'
      
class Follow(TimeStampModel): 
    follow_from = models.ForeignKey('User',on_delete=models.CASCADE,related_name='follow_from')
    follow_to = models.ForeignKey('User',on_delete=models.CASCADE,related_name='follow_to')
    #related_name이 같거나 설정해주지 않으면(즉 default로 같아지면), 에러가 발생함

    class Meta:
        db_table='follows'

 

Views

  • 로그인 상태여야 하므로, access_token_check decorator를 사용
    • 또한 access_token을 활용해, 현재 유저가 누구인지를 식별
  • follow하려는 대상의 정보를 고유한 email로 받는다고 가정
  • 좋아요가 존재할 경우, 유저간의 관계를 나타내는 중간테이블에서 두 유저사이의 관계를 삭제
  • 반대로 좋아요가 없을 경우, 중간 테이블에서 두 유저사이의 관계를 생성.
#views.py
class LikeView(View):
    @access_token_check
    def post(self,request):
        data = json.loads(request.body)
        user = self.user
        try:
            follow_to_email = data['follow_to_email']#이메일로 받지 않을까??
            follow_to       = User.objects.get(email = follow_to_email)
            if Follow.objects.filter(follow_from=user,follow_to=follow_to).exists():
                Follow.objects.filter(follow_from=user,follow_to=follow_to).delete()
                return JsonResponse({"message":"팔로우가 취소되었습니다!"},status=201)

            Follow.objects.create(
                follow_from=user,
                follow_to=follow_to,
                )

            return JsonResponse({"message":"팔로우가 등록되었습니다!"},status=201)

        except KeyError:
            return JsonResponse({"message":"KEY_ERROR"},status=400)
        except User.DoesNotExist:
            return JsonResponse({"message":"NOT_REGISTERED_EMAIL"},status=401)

BELATED ARTICLES

more