Westagram #4 : 좋아요 기능 구현 + related_name

채록·2021년 2월 13일
1

Python & Django

목록 보기
22/34
post-thumbnail

좋아요 기능

한 유저가 '좋아요' 표시를 한 게시글은 빈 하트에서 ❤️ 하트로 바뀐다. 이 영역을 프론트의 영역이지만 어떤 정보를 받아서 변하는지는 백.. 쪽이라 생각한다.. (예를들어 0일땐 빈 하트, 값이 1일땐 ❤️ )




좋아요 기능 Flow

  • 게시글에 관련된 행동이므로 posting app 에서 작업했다.
  • Like라는 class에 행동할 user와 좋아요 누를 posting. 유저 두가지 user field를 만든다. (두가지 모두 FK)
  • 행동할 user가 게시글을 '좋아요'할때 두 FK의 id 값이 likes table에 저장된다.
  • 테이블에 새로운 instance가 생성되는 시점을 기록한다. create_at


models.py

class Like(models.Model):
    user    = models.ForeignKey(User, on_delete=models.CASCADE)
    posting = models.ForeignKey(Posting, on_delete=models.CASCADE)
    create_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'likes'

views.py : LikeView

  • 로그인한 유저가 아니더라도 일단 likes 에 저장된 data를 get 할수 있게 했다. (실제 인스타에서 사용하는 일은 못본거 같다. 단순 데이터 확인용)
  • likes table의 새 instance 생성시 필요한 user에 대한 값은 token으로부터 받아오게 하였다.
  • reqeust.body에는 어떤 게시글인지 posting의 id값이 들어있어야 한다.

ManyToMany Field 활용하기

  • Posting과 User는 ManyToMany관계이다. 위의 models.py에서 보면 user와 posting 외에 create_at 이라는 추가 field를 생성하기 위해 table을 먼저 만들었는데 저게 없었다면 잠시동안은 table 없이도 값을 추가하는데 큰 지장이 없었을 것이다. (instance가 1~2개라면 관리하기 어렵지 않을 테지,,)

  • likes table에 값을 생성하는 두가지 방법을 모두 기록했다.

    1. postings table에서 정참조 관계인 like_user에 접근해 add를 사용해 생성
    2. likes table에 직접 생성



related_name

위에서 1번의 경우를 사용하려면 Posting class에 User class를 또 FK로 지정해 주저야 한다.
하지만, 이미 게시글을 올리는 유저 라는 뜻으로 User를 FK로 지정해 줬었다. 한번 FK 지정에 사용한 class를 별도 옵션 없이 또 다시 지정하려니 다음과 같은 에러가 발생했다.

django 에서는 한가지 class를 서로 다른 용도로 FK 지정을 해준다 하여도 그 두가지를 비교할 수 없다. User class에서 게시글을 올린 사람을 뜻하는 user인지, 그 게시글을 '좋아요'한 user인지 구분 X 이럴때 새로운 이름을 부여해 준다. related_name !!

참고로 나는 저 작업을 할때 runserver중이어서 실시간으로 에러가 발생했는데, 이 상태에선 어차피 migration도 안된다고 한다 😅 누가? 빛소헌님이..!

따라서 Posting class에 다음과 같이 작성해 주었다.

class Posting(models.Model):
    user        = models.ForeignKey(User, on_delete=models.CASCADE)
    image_url   = models.URLField(max_length=2000)
    description = models.CharField(max_length=100, null=True)
    create_at   = models.DateTimeField(auto_now_add=True)
*   like_user   = models.ManyToManyField(User, through='Like', related_name='like_user')

    class Meta:
        db_table = 'postings'
  • 게시글 올린이와 구분하기 위해 user가 아닌 like_user라고 이름지었다.
  • 'Like' class를 통해 User와 MtoM 관계임을 명시하고, 이때 사용되는 user는 like_user라고 related_name을 지었다.

django shell 로 동작 확인하기

django shell을 통해 정상적으로 작동함을 확인하였다.

!!!!오타!!!!!

>>> like_3 = post.objects.add(User.objects.get(id=30))

이 아니라...

>>> like_3 = post.like_user.add(User.objects.get(id=30))

이거당



views.py : LikeDetailView

  • 특정 게시글에 몇개의 '좋아요'가 있는지 갯수를 알려주는 get 기능 구현.
  • 좋아요 취소를 할 경우 likes table에서 해당 instance가 삭제되게 한다.

=> 두가지 모두 어떤 게시글인지 특정되어야 한다. 이 정보는 url에 담기게 한다.


  • url에 없는 posting의 id를 입력하면 INVALID_POST가 뜬다.
  • 좋아요 갯수가 하나도 없는 게시글이라면 빈 list가 아닌 NONE_HEART가 뜬다. 에러가 아니기 때문에 status=200으로 했다.
  • 좋아요 갯수는 좋아요 객체들이 담긴 list의 갯수 (length)를 세는 방식으로 작성했다.

  • 토큰에 담긴 user가 작성한 게시글이 url에 담긴 게시글의 id와 일치하는 것이 있을 때 해당 instance는 삭제된다.
    => 한 유저가 하나의 게시글에 여러번 좋아요를 할 순 없다.! 해당 값에 대한 instance는 최대 한개이다.
  • 이미 삭제되어서 없거나, 혹은 애초에 존재하지 않는 instance를 찾을때 Like.DoesNotExist에러가 발생한다. 이때 메세지를 INVALID_LIKE로 보내도록 했다. 없는 것을 찾으므로 status=400



제일 위에서 말했던 것처럼 1일땐 좋아요, 0일땐 아닌 상태로 표기하게 하는 것이 더 좋을것 같다. 하지만 아직 그거까진 생각을 못했고 일단 단순하게 ManyToManty Field를 활용해 좋아요 상태인 유저-게시글관계에 대한 새로운 instance를 생성하게 했다.

다음 글은 다른 계정 Follow 에 대해 쓸 것.




🔥🔥🔥🔥 잘못사용한 개념 (21.02.19 추가)

related_name 개념을 잘못 이해했었다. 수정된 개념에 대한 포스팅 참고하자

profile
🍎 🍊 🍋 🍏 🍇

2개의 댓글

comment-user-thumbnail
2021년 11월 22일

안녕하세요 좋아요 기능 관련해서 좋은 레퍼런스가 되었습니다 감사해요 :)
또한 깔끔한 글을 보다가.. 코드 첨부하실 때 맥북처럼 어떻게 하셨는지 궁금해졌습니당 .. 정보 부탁드려도 될까용 ..!

1개의 답글