Skip to content

dth12/movie-community

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

신박한 영화

Intro.

TMDB API와 YOUTUBE API를 활용한 신박한 영화 정보 제공커뮤니티 사이트입니다.

Architecture

django

  • django rest framework
  • image-kit
  • simple jwt
  • django cors headers
  • requests

vue.js

  • vuex

  • vue-router

  • axios

  • vue-bootstrap

  • hooper (swiper)

  • vue-js-modal

  • vue-starating

  • vue-loading-overlay

  • vue-fontawesome

Roles

Back과 front를 분리하지 않았고, 초반 설계를 같이 진행했다.

박지수

  • 영화 메인, 디테일
  • 영화 추천
  • 영화 검색

신동윤

  • 영화 커뮤니티 디자인
  • backend에서 model 수정

목표 구현율

추가로 아래와 같은 기능을 추가하려했으나,

  • 예상 별점
  • 내 폴더 기능
  • 성별 및 연령대별 별점 필터링

짧은 프로젝트 기간으로 인해, 주요기능에 충실하고자 했습니다.

ERD

![Image Pasted at 2021-5-27 14-14](README.assets/Image Pasted at 2021-5-27 14-14.png)

User와 movie 두 개의 모델을 중심으로 Comment, RatedMovie, LikedMovie 등을 1:N 또는 M:N으로 모델링했습니다.

주요기능

1. 메인페이지

메인

기능

  • 검색기능
  • 가장 인기 많은 영화의 트레일러
  • 인기영화, 현재 상영작, 이번 주 인기작 정보 제공
  • 화면에 존재하는 포스터를 클릭하면 모두 디테일 페이지로 이동

디자인

  • Navbar 아래에 tmdb의 backdrop_path를 통한 그라데이션 백그라운드

  • 마우스 hover에 반응형으로 제작.

  • Hooper swiper를 이용해 마우스 클릭 또는 드래그로 다양한 영화 정보를 한번에 제공.

2. 디테일 페이지

디테일

기능

  • starating를 통해 클릭 또는 드래그로 별점 매기기.

  • 현재 우리 사이트에 가입한 유저가 매긴 평점의 평균 및 유저가 누른 좋아요 수 제공

  • TMDB 사이트의 정보 제공 (배우 정보, TMDB 평점 및 투표수, overview 등)

  • 하단에 현재 디테일 페이지 상의 영화와 관련된 유사 영화 제공

  • comment 클릭 시, 댓글 페이지로 이동 가능

디자인

  • starating을 사용하여, 별점 주기 편의성을 높임.
  • 그라데이션 백그라운드
  • bootstrap icon을 통해 알아보기 쉬운 아이콘 삽입.

3. 댓글 페이지

디테일 페이지에서 comment 클릭 시, 베스트 댓글 모음 modal 등장

1) 베스트 댓글

베댓

기능

  • 디테일 페이지의 영화 댓글 중, 가장 좋아요가 많은 순서로 보여줌.
  • 긴 댓글의 경우에 전부 보여주지 않음.
  • more comments 버튼을 통해 댓글 상세 페이지로 이동 가능
  • 좋아요 누르기 가능

디자인

  • vue-js-modal을 통해 쉽게 댓글 파악가능
  • 작성자 옆에 프로필 사진 삽입
  • boostrap icon 사용

2) 댓글 상세 페이지

댓글2

댓글3

기능

  • 댓글 작성 버튼 클릭 시, 댓글 작성 modal이 발생하고 작성가능.

  • 각 댓글에 대한 대댓글 작성 가능

  • 자신이 단 댓글에 한해 삭제 및 수정 가능

  • 각 유저가 매긴 별점이 존재할 시, 좌측 상단에 댓글 쓴 유저의 별점 제공.

4. 추천 페이지

상단 navbar에서 Recommendation 클릭 시, 추천 페이지로 이동

추천1

추천2

기능

  • 내가 최근에 좋아요를 누른 순서로 선택할 수 있는 화면 제공.
  • 마음에 드는 영화 클릭 시, TMDB의 recommendation을 통해 영화 추천.
  • 영화 클릭 시, 디테일 페이지로 이동.

디자인

  • 영화 포스터 hover 시, 팝업 기능.

5. 검색

검색

기능

  • 상단 navbar의 search 창에 검색 후, enter 또는 돋보기 버튼 클릭 시 검색 가능
  • 맨위에 검색 결과를 제공
  • 하단 similar movie에서는 검색 결과와 관련된 영화를 제공
  • 포스터 클릭 시, 디테일로 이동.

6. 프로필

프로필

프로필2

프로필3

기능

  • 상단 우측, profile 버튼 클릭 시 이동가능
  • 내 프로필에서는 설정버튼을, 다른 사람의 프로필에서는 팔로우 버튼을 제공
  • 아래에 내가 좋아요와 평가한 영화 정보를 제공 클릭시 디테일 이동.
  • 설정 클릭 시, 정보 수정 또는 탈퇴 선택.
  • 탈퇴 클릭 시, 귀여운 경고 문구와 함께 탈퇴여부 선택

7. 회원정보 수정

회원정보수정2

회원정보수정2

회원정보수정3

기능

  • 회원정보 조회 및 수정 가능
  • 수정 버튼 클릭 시 수정 모드 진입
  • 이미지 프로필도 수정가능하며, 업로드를 하지 않을 시 기본 이미지 제공.
  • 또한 여기 클릭 시 비밀번호 변경가능하며, 정보 오류 시 경고 문구.

8. admin

회원정보수정3

어드민2

기능

  • 관리자 계정으로 로그인 시 우측 상단에 admin 태그 노출.
  • 클릭 시 admin 페이지로 이동.

client

vuex

  • vuex 사용 시 비동기적 처리에서 어려웠으며, 지역적으로 사용할 경우에는 component 내에서 method와 state를 정의하는 게 훨씬 좋았다.
  • state를 다시 computed에 넣어서 관리할 경우, 데이터의 동작시기가 달라 예상치 못한 에러가 발생했다.
  • v-if 등으로 데이터가 존재할 때에만 동작하도록 하여 에러를 해결했다.
  • vuex에서도 프로젝트의 규모가 커지면서 모듈로 나누어 관리용이성을 증가시켰다.

axios

  • axios의 default 값(intercept, baseurl)을 변경했을 때, 모든 axios에서 적용이 되어서 원하는 결과를 얻지 못했다.
  • 그래서 이후, axios 요청마다 따로 header 또는 URL를 지정하여 해결하였다.
  • get의 경우 2번째 인자로 header를 받고, post, put 등은 3번째 인자로 header를 받았는데 전부 두번째에 넣어서 오류가 발생했다.
  • 즉 헤더가 아닌 payload로 보냈고, 이후 Network 탭에서 오류를 발견하고 수정하였다.

라이브러리

  • 라이브러리 이용할 때 README가 부실하여 처음에 재대로 사용하기 어려웠다.
  • 다양한 예제를 검색하고, 직접 node module 안에 있는 코드도 수정하며 우리가 사용하고자 하는 방향으로 이끌었다.
  • vue-js-modal은 웬만하면 사용하지 말자!

transition

  • 넷플릭스의 모달과 같은 효과를 주기 위해서, transition이라고 하는 css 구문 사용했다.
  • 자연스럽게 요소가 선택되었다는 것을 보여줄 수 있다.

UX

  • 유저에게 선택가능함을 알려주기 위해, 선택 가능한 요소에 대해 cursor를 pointer로 변경해주었다.
  • 데이터를 서버나 API로부터 가져오는데 시간이 소요되기 때문에 로딩 페이지를 넣어 사용자가 그 시간을 인식할 수 있게끔 해주었다.
  • modal를 통해 이동하지 않고도 수정과 작성이 가능하게 하였다.
  • starating으로 손쉽게 별점을 줄 수 있도록 하였다.
  • router 사용해서 URL만 변경함으로써 사용자에게 페이지를 이동했음을 인식시키고 히스토리 모드를 통해 뒤로가기가 가능하게 했다.

router

  • router 전역 가드를 통해 로그인 시에만 서비스에 접근할 수 있도록 제한하였다.
  • 비로그인 시에는 회원가입과 로그인 페이지만 갈 수 있도록 하였다.
  • 동적 라우팅(query, params)을 이용해 URL 자체에 정보를 실었다.

localstorage

  • 로컬 스토리지에는 모든 것이 문자열로 저장된다.
  • 만약 새로고침을 하더라도 정보가 필요할 시, 민감한 정보가 아니라면 로컬에 저장하자.

파일 관리

  • 애초에 component를 생성할 때, 파일 구조를 잡아서 생성하도록 하자.
  • 프로젝트 규모가 커지면 관리가 힘들다.

Component

  • 만약 디테일 페이지에서 디테일 페이지로 넘어갈 경우에는created와 같은 life cycle hook이 작동하지 않는다.
  • 이럴 때에는, 동적 라우팅을 이용하여 watch로 $route 를 감시하여 변경 사항을 적용한다.
  • style의 경우에도 computed를 활용할 수 있다.

server

  • 모델 설계를 잘하자!!! 나중에 수정하려면 front-end도 모두 수정해야할 수도 있다.

Model

from django.db import models
from django.conf import settings
from django.db.models.fields import CharField

User = settings.AUTH_USER_MODEL

class Movie(models.Model):
    tmdb_id = models.CharField(max_length=50, unique=True)
    title = models.CharField(max_length=100, null=True)
    poster_path = models.CharField(max_length=200, null=True)
    backdrop_path = models.CharField(max_length=200, null=True)
    like_users = models.ManyToManyField(User, related_name='like_movies')


class Comment(models.Model):
    like_users = models.ManyToManyField(User, related_name='like_comments')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='comments')
    content = models.CharField(max_length=1000)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class ReComment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    comment = models.ForeignKey(Comment, on_delete=models.CASCADE, related_name='recomments')
    content = models.CharField(max_length=1000)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class RatedMovie(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='rated_movies')
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='rates')
    rate = models.IntegerField()

URL

# movie_api/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    # TokenRefreshView,
)

urlpatterns = [
    path('admin/', admin.site.urls), # GET admin 페이지
    path('api/v1/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # POST 로그인 시 토큰 발행.
    path('api/v1/accounts/', include('accounts.urls')), # accounts
    path('api/v1/movies/', include('movies.urls')), # movies
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # media 파일 저장을 위한 URL 및 root
# movies/urls.py
from django.urls import path
from . import views
urlpatterns = [
    path('<int:tmdb_id>/comment/', views.comment_list_create), # GET POST comment 관련 정보 저장 및 조회
    path('<int:tmdb_id>/comment/<int:comment_id>/', views.comment_update_delete), # PUT DELETE 댓글 수정 및 삭제.
    path('<int:tmdb_id>/like/', views.movie_like,), # POST 영화 좋아요 수정 및 생성
    path('comments/<int:comment_id>/like/', views.comment_like,), # GET POST 댓글 좋아요 및 좋아요 조회
    path('<int:tmdb_id>/rate/', views.movie_rate), # GET POST 영화 평점 수정 및 생성
    path('<int:comment_id>/recomment/', views.recomment_list_create), # GET POST 대댓글 생성 및 조회
    path('<int:comment_id>/recomment/<int:recomment_id>/', views.recomment_delete), # DELETE 대댓글 삭제
    path('<int:tmdb_id>/like/rate/', views.get_like_rate), # GET 영화 좋아요 및 별점 조회
    path('<int:tmdb_id>/comments/best/', views.get_best_comment), # GET 베스트 댓글 조회
    path('<int:tmdb_id>/', views.set_initial_movie_info), # POST 영화 디테일 페이지 최초 진입 시에만 저장
    path('<int:tmdb_id>/backdrop/', views.get_backdrop), # GET 영화 뒷배경 가져오기.
]
# accounts/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('signup/', views.signup), # POST 회원가입
    path('users/', views.user_update_delete), # GET PUT DELETE 유저 회원정보 수정 및 삭제 그리고 조회
    path('password-change/', views.user_password_change), # PUT 비밀번호 변경
    path('<username>/follow/', views.follow), # GET POST 유저 팔로우 정보 조회 및 수정
    path('issuperuser/', views.is_superuser), # GET 슈퍼 유저인지 판별.
    path('<username>/user/movies/', views.user_movie_info), # GET 유저의 rated movie & liked movie 정보 조회
]

serializers

  • 이번 프로젝트에서 가장 많이 쓴 serializer method
  • get_<field_name>으로 작성 시, 새로운 필드를 serializer 추가 가능
class CommentListSerializer(serializers.ModelSerializer):
    username = serializers.SerializerMethodField()
    
    # 이건 read_only
    # get_<field_name>으로 메서드 생성
    # self => instance, obj => Model
    def get_username(self, obj):
        return obj.user.username
    
    ...
    	fields=(...'username',) # 이렇게 추가.

Pin.

지수

  • 동윤님과 함께 하면서 즐거웠다.
  • 원래는 백엔드만 생각했었는데, 프론트도 하다보니 흥미가 생겨서 이 분야도 고려해봐야겠다.

동윤

  • 지수님과 함께 하면서, css와 디자인에 대해 많이 배울 수 있었다.
  • 프로젝트 기간이 정말 짧고 힘들었지만, 같이 하다보니 재밌게 잘 끝낼 수 있었다.
  • 앞으로의 세번의 프로젝트도 잘 끝내고 싶다.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published