Leta Learns

영화 평가 사이트 | 210725 본문

멋쟁이사자처럼 9기/미니 해커톤

영화 평가 사이트 | 210725

leta 2021. 7. 27. 01:01

 

둘째 날은 디테일 페이지 마무리 하고 css 작업 진행했다.

 

 

 

1. detail 마무리

팀원이 올린 staff 클래스 받아와서 디테일 페이지에 staff 정보까지 띄웠다. 이때 깃으로 받아오는 과정에서 또 문제가 생겨서 30분 넘게 지연됐다. 첫째 날에는 시간이 좀 있어서 깃으로 주고 받았는데 둘째 날은 아무래도 전 날보다 시간에 쫓겨서 후반에는 카톡으로 코드를 주고 받기도 했다. 완성은... 해야하니까..

 

staff 정보 올린 후에는 다른 팀원이 올린 comment 클래스도 받아와서 댓글 작성 기능을 구현했다. 이것도 역시나. 깃으로 하다가 애먹고 혼났다. ㅎㅎ 시간 내에 완성해야 하니 간단한 코드는 그냥 카톡으로 주고 받으라 했거든...

 

 

팀원들 작업물과 내 작업물을 합친 전반적인 blog앱 작업물들

 

models.py

from django.db import models
from account.models import CustomUser

# Create your models here.
class Movies(models.Model):
    title_kor= models.CharField(max_length=200)
    title_eng= models.CharField(max_length=200)
    poster_url= models.CharField(max_length=500)
    rating_aud= models.CharField(max_length=200)
    rating_cri= models.CharField(max_length=200)
    rating_net= models.CharField(max_length=200)
    genre= models.CharField(max_length=200)
    showtimes= models.CharField(max_length=200)
    release_date= models.CharField(max_length=200)
    rate= models.CharField(max_length=200)
    summary= models.CharField(max_length=200)

class Staff(models.Model):
    number = models.ForeignKey(Movies, null=True, on_delete=models.CASCADE)
    name= models.CharField(max_length=200)
    role= models.CharField(max_length=200)
    image_url= models.CharField(max_length=500)

class Comment(models.Model):
    movie = models.ForeignKey(Movies, null=True, on_delete=models.CASCADE, related_name="comments")
    comment_user = models.ForeignKey(CustomUser, null=True, on_delete=models.CASCADE)
    comment_body = models.CharField(max_length=200)
    comment_date = models.DateTimeField()
    class Meta:
        ordering = ['comment_date']

 

admin.py

from django.contrib import admin
from .models import Movies, Staff, Comment

# Register your models here.
admin.site.register(Movies)
admin.site.register(Staff)
admin.site.register(Comment)

 

views.py의 init_db 요청할 때 db가 계속 안 받아지는 에러가 났다. db.sqlite3 지우고 해당 앱(blog)의 migrations 폴더 지운 후 다시 makemigrations, migrate 하니까 해결 됐다. 

home 함수에 init_db(request)를 계속 써놓으면 home 함수가 호출될 때마다 db가 추가돼서 처음에 home 열 때만 적어주고 그 뒤로는 home함수에서 그 부분을 삭제하였다.

views.py

from django.shortcuts import render , redirect, get_object_or_404
from .models import Movies,Staff,Comment
from django.core.paginator import Paginator
import requests
from account.models import CustomUser
from django.utils import timezone
from requests.api import get

# Create your views here.
def home(request):
    query= request.GET.get('query')
    if query:
        blogs= Movies.objects.filter(title_kor__icontains=query)
    else:
        blogs= Movies.objects.all()

    paginator= Paginator(blogs, 8)
    page= request.GET.get('page')
    query = request.GET.get('query')
    paginated_blogs= paginator.get_page(page)
    if query:
        return render(request, 'home.html', {'blogs': paginated_blogs, 'query': query})
    else:
        return render(request, 'home.html', {'blogs': paginated_blogs})

def init_db(request):
    url = "http://3.36.240.145:3479/mutsa"
    res = requests.get(url)
    movies = res.json()['movies']
    for movie in movies:
        new_movie = Movies()
        new_movie.title_kor = movie['title_kor']
        new_movie.title_eng = movie['title_eng']
        new_movie.poster_url = movie['poster_url']
        new_movie.rating_aud = movie['rating_aud']
        new_movie.rating_cri = movie['rating_cri']
        new_movie.rating_net = movie['rating_net']
        new_movie.genre = movie['genre']
        new_movie.showtimes = movie['showtimes']
        new_movie.release_date = movie['release_date']
        new_movie.rate = movie['rate']
        new_movie.summary = movie['summary']
        
        new_movie.save()

        for stf in movie['staff']:
            new_stf = Staff()
            new_stf.number = new_movie
            new_stf.name = stf['name']
            new_stf.role = stf['role']
            new_stf.image_url = stf['image_url']

            new_stf.save()
        
    return redirect('home')

def detail(request, id): 
    blog = get_object_or_404(Movies, pk = id) 
    staffs = Staff.objects.filter(number=id)
    comments = Comment.objects.filter(movie=id)
    return render(request, 'detail.html', {'blog': blog,'staffs':staffs, 'comments':comments})

def create_comment(request):
    if request.method == "POST":
        comment=Comment()
        comment.comment_body = request.POST.get('comment_body', '')
        comment.movie = Movies.objects.get(pk=request.POST.get('movie_id'))
        writer = request.user
        print(writer)
        if writer:
            comment.comment_user = CustomUser.objects.get(username=writer)
        else:
            return redirect('blog:detail', comment.movie.id)
        comment.comment_date = timezone.now()
        comment.save()
        return redirect('blog:detail', comment.movie.id)
    else:
        return redirect('home')

 

urls.py

from django.contrib import admin
from django.urls import path
from blog.views import *

app_name='blog'

urlpatterns = [
    path('admin/', admin.site.urls),
    path('<int:id>', detail, name='detail'),
    path('create_comment/', create_comment, name='create_comment'),
]

 

 

 

 

 

2. CSS

예상하긴 했지만.. 난 정말 CSS가 너무 싫다.. detail 페이지 조금 하다가 막혀서 운영진 선배가 거의 다 도와줬다. 나는 댓글 부분 CSS로 정리해줬다.

 

home.html

{% extends 'base.html' %}
{% load static %}
{% block content %}
  <head>
    <style>
      body {background-color: rgb(233, 233, 233);}
    </style>
  </head>

  <div style="background-color: white;">
    <br> <br>
    <img src="{% static 'Main.PNG' %}" alt="" width="1200px">
    <div class="new-movie">
      <h4 style="text-align: left; margin-top: 50px; margin-left: 30px; margin-bottom: 50px;">NEW & UPCOMING MOVIES</h4>

      <div class="row">
          {% for blog in blogs%}
          <div class="col-md-3">
            <table class="table" style="list-style: square;">
              <a href="{%url 'blog:detail' blog.id %}"><img src="{{blog.poster_url}}" alt=""></a>
            <tr>
            <h6 style="margin-top: 10px; margin-bottom: 40PX;" ><a href="{%url 'blog:detail' blog.id %}" style="text-decoration: none; color: black;">{{ blog.title_kor }}</a></h6>
          </table>
          </div>
          {% endfor %}
      </div>
    </div>
    
    <br/>

    <div class="paginator">
      {% if blogs.has_previous %}
     
      <strong><a href="?page=1&query={{query}}"  style="margin-right: 5px; text-decoration: none; color: black;">처음</a></strong>
      <strong><a href="?page={{blogs.previous_page_number}}&query={{query}}"  style="margin-right: 10px; text-decoration: none; color: black;">이전</a></strong>
      {% endif %}
      <span>{{blogs.paginator.num_pages}}</span>
      <span>페이지 중에</span>
      <span>{{blogs.number}}</span>
      <span>페이지 입니다</span>
      {% if blogs.has_next %}
      <strong><a href="?page={{blogs.next_page_number}}&query={{query}}"  style="margin-left: 10px; text-decoration: none; color: black;">다음</a></strong>
      <strong><a href="?page={{blogs.paginator.num_pages}}&query={{query}}" style="margin-left: 5px; text-decoration: none; color: black;">마지막</a></strong>
      {% endif %}
    </div> <br>
  </div>
  
  <footer style="text-align: center; margin-top: 40px; margin-bottom: 20px; text-align: center;">
    Copyright © Fandango. All rights reserved. V3.1 Privacy Policy  Terms and Policies  Do Not Sell My Info  AdChoices
  </footer>
{% endblock %}

 

detail.html

{% extends 'base.html' %}
{% load static %}
    {% block content %}
    <head>
      <style type="text/css">
        textarea { 
          resize: none;
          width: 100%;
        }

        #poster {
          margin-right: 20px;
        }
        * {
          text-align: left;
        }
        .container {
          display: block
          margin: 0 auto
        }
        #detail {
          width: 500px;
        }
        .title_eng{
          font-size: medium;
        }
        #information {
          display: flex;
        }
        .staff {
          display: flex;
        }
        #each-staff {
          margin-right: 20px;
        }
        #each-staff > p {
          margin: 0
        }
        .name > p {
          font-size: 30px
        }
        #maketext {
          width: 100%;
          display: flex;
          justify-content: flex-start;
        }
        h3 {font-weight: 600;}
      </style>
    </head>
    <div id="total"><br>
      <h3 style="font-size: 26pt;">{{blog.title_kor}} &nbsp; <span class="title_eng">{{blog.title_eng}} </span> </h3>
      <div id='information'>
        <img id='poster' src="{{blog.poster_url}}" width=280 />
        <div id="detail">
          <span><strong>관람객 평점</strong> {{blog.rating_aud}}</span><br>
          <span><strong>평론가 평점</strong> {{blog.rating_cri}}</span><br>
          <span><strong>네티즌 평점</strong> {{blog.rating_net}}</span><br>
          <br>
          <span><strong>장르</strong> {{blog.genre}}</span><br>
          <span><strong>상영 시간</strong> {{blog.showtimes}}</span><br>
          <span><strong>상영 등급</strong> {{blog.rate}}</span><br>
          <span><strong>개봉일</strong> {{blog.release_date}}</span><br>
          <br>
          <p><strong>줄거리</strong></p>
          <p>{{blog.summary}}</p>  
        </div>
      </div>
      <br>
      <div class="name">
        <p>인물 정보</p>
      </div>
      <div class='staff'>
        {% for staff in staffs %}
        <div id="each-staff">
          <img src="{{staff.image_url}}" />
          <p>{{staff.role}}</p>
          <p>{{staff.name}}</p>
        </div>
        {% endfor %}
      </div>
      <hr/>
  
    </div>

        <!-- 여기부터 코멘트 -->
        <div>
          {% if question.comment_set.count > 0 %}
            {% for comment in question.comment_set.all %}
              <span>{{ comment.content }}</span>
              <span>
                글쓴이: {{ comment.author }}
            </span>
            {% endfor %}
          {% endif %}
        </div>
        <div>
          <div>
            {% for comment in comments %}
            <h5>{{ comment.comment_user }}</h5>
            <span style="text-indent: 20px;">
            <h5>{{ comment.comment_body }}</h5>
            <h6>{{ comment.comment_date }}</h6></span><hr/>
            {% endfor %}
          </div>
          
            <form method="post" action="{% url 'blog:create_comment' %}">
                {% csrf_token %}
                <div>
                    <label for="content">한 줄 평가</label><br>
                    <div id="maketext">
                      <input name="movie_id" value="{{blog.id}}" hidden>
                      <textarea name="comment_body" width=100%>{{ form.content.value|default_if_none:'' }}</textarea>
                      <button type="submit" style="width: 100px; text-align: center;">저장하기</button>
                    </div>
                </div>
                
            </form>
        </div>
        </div>
        
    <footer style="text-align: center; margin-top: 40px; margin-bottom: 20px; text-align: center;">
      Copyright © Fandango. All rights reserved. V3.1 Privacy Policy  Terms and Policies  Do Not Sell My Info  AdChoices
    </footer>
    {% endblock %}

 

login.html

{% extends 'base.html' %}
{% block content %}

<head>
  <style>
    .login_div {width: 45%; border-radius: 60px; padding: 60px; 
    border: 1px lightgray solid; background-color: whitesmoke;
    position: relative; top: 250px; left: 300px; text-align: left;
    }
    .login_button { border: none; background: none; float: right;}
    .login_h1 {font-weight: bolder;}
  </style>
</head>

<div class="login_div">
  <h1 class="login_h1">Login</h1> <br>
  <form action="{% url 'account:login' %}" method="POST">
  {% csrf_token %}
  {{form.as_p}}
  <button type="submit" class="login_button">Login</button>
</form>
</div>


{% endblock %}

 

signup.html 회원가입 페이지는 CSS 적용하는 거 까먹고 있다가 마감 시간 30분 전에 깨달아서 조금만 바꿔주었다.

{% extends 'base.html' %}
{% load static %}

{% block content %}

<head>
  <style>
    .helptext, li {
      display: none;
    }
    button {
      border: 1px solid black;
      border-radius: 5px;
      background: blue;
      color: white;
      font-weight: bold;
    }
    .signup_div { position: relative; top: 220px;}
  </style>
</head>

<div class="signup_div">
<h1>Sign Up</h1> <br>
<form action="{% url 'account:signup' %}" method="POST">
  {% csrf_token %}
  {{form.as_p}}

  <button type="submit">회원가입</button>
</form>
</div>
{% endblock %}

 

 

 

 

3. 검색 기능 Pagination

home페이지에서 검색을 하면 검색한 글자가 들어가는 영화 제목을 전부 찾아주는 search 기능이 있다.

home에서 8개 씩 paginator를 해주었는데 검색 결과가 8개를 넘어가면 다음 페이지에서는 쿼리가 저장되지 않아서 검색 결과가 아닌 그냥 db에 담긴 영화들이 나왔다. (검색 결과 목록의 2번째 페이지가 아니라, home의 기본 영화 목록에서의 2번째 페이지)

views.py에서 home 함수를 고치고 home.html에서 paginator에 해당하는 부분의 url을 고쳐주었더니 해결되었다. 사실 써놓고 안 돌아가는 줄 알고 다른 방법 구글링해보고 있었는데 다시 실행해보니 제대로 돌아가서 당황했다. 난 무엇을 구글링 하였는가.. 구글링 해도 아무것도 안 나오긴 했다..

 

views.py

1에서 올린 views.py와 동일. home함수 부분만 보면 됨

def home(request):
    query= request.GET.get('query')
    if query:
        blogs= Movies.objects.filter(title_kor__icontains=query)
    else:
        blogs= Movies.objects.all()

    paginator= Paginator(blogs, 8)
    page= request.GET.get('page')
    query = request.GET.get('query')
    paginated_blogs= paginator.get_page(page)
    if query:
        return render(request, 'home.html', {'blogs': paginated_blogs, 'query': query})
    else:
        return render(request, 'home.html', {'blogs': paginated_blogs})

 

 

home.html

2에 올린 home.html에서 <div class="paginator"> 이 부분만 보면 된다.

처음을 제외한 모든 paginator 링크에 page 정보와 query정보를 넣어주었다. (?page={{page}}&query={{query}})

    <div class="paginator">
      {% if blogs.has_previous %}
     
      <strong><a href="?page=1&query={{query}}"  style="margin-right: 5px; text-decoration: none; color: black;">처음</a></strong>
      <strong><a href="?page={{blogs.previous_page_number}}&query={{query}}"  style="margin-right: 10px; text-decoration: none; color: black;">이전</a></strong>
      {% endif %}
      <span>{{blogs.paginator.num_pages}}</span>
      <span>페이지 중에</span>
      <span>{{blogs.number}}</span>
      <span>페이지 입니다</span>
      {% if blogs.has_next %}
      <strong><a href="?page={{blogs.next_page_number}}&query={{query}}"  style="margin-left: 10px; text-decoration: none; color: black;">다음</a></strong>
      <strong><a href="?page={{blogs.paginator.num_pages}}&query={{query}}" style="margin-left: 5px; text-decoration: none; color: black;">마지막</a></strong>
      {% endif %}
    </div> <br>
  </div>

 

 

 

 


 

 

 

영화 평가 사이트 최종 구현 후 실행 영상

 

 

첫 번째 미니 해커톤 잘 완료해서 기분이 좋다. 하지만.. 재밌는 건 재밌는 거고 내 실력은 정말 말이 안 나왔다. 장고 복습 몇 번 했다고 익숙해지지 않는구나. 확실히 직접 플젝을 하니까 훨씬 더 많이 익숙해진 것 같다. 다음 해커톤 전까지 다른 사람이랑 같이 아니면 혼자라도 한 번 더 연습해보려고 한다.

 

해커톤에 주말을 다 사용해야 하니 다른 일을 미리 해둬야 해서 일주일 내내 바빴다. 해커톤 하는 동안에도 잠을 많이 못 잤고.. 하루종일 코딩하고 잠 조금 자고 집에서 한 시간 거리를 이동하려니 체력이 모자라서 컨디션이 점점 엉망이었다. 둘째 날에는 마감 전 까지 할 일이 아직 많아서 점심도 안 먹었더니 더 힘들었다. 게다가 내가 발표하게 돼서 ㅋㅋ 발표할 땐 완전 넋이 나가있었다.

 

기능 구현 다 하고 CSS 해야 할 때는.. 진짜 너무 하기 싫어서 텐션이 더 낮아졌었다. 팀원들한테 미안하다.. 끝까지 정신 차리고 CSS도 잘 했었어야 하는데 :( 다음 번에는 멘탈 꼭 붙잡고 CSS까지.. 꼭 하겠습니다.. (이번 해커톤을 통해 또 한 번 나는 CSS를 너무너무 싫어한다는 것을 깨달았다).

 

프로젝트 하면서 영화 정보 데이터 받아오는 작업이 있었는데 다른 팀원이 도맡아해서 나는 신경도 안 썼다. 그 부분은 내가 따로 공부해봐야 할 것 같다. 작년 여름 웹 개발 공부할 때 API 통신으로 데이터 받아온 경험이 있긴 한데 오래돼서 기억도 안 난다. 이 부분 다시 공부해야지.

 

이번 해커톤 그래도 뿌듯하다 ! 아쉬운 점은 깃만 좀 더 잘 알았다면 ㅠ 우리 팀 모두 깃에 미숙해서 시간을 많이 잡아먹은 게 아쉽다. 깃 진짜 연습할거야. 그리고 장고 프로젝트 할 때 항상 파이참을 썼었는데 이번 해커톤에서는 vscode를 사용했다. vscode에서 장고 돌리는 법 모르고,, 파이참에서는 알아서 해주는 일을 vscode는 수동으로 해야 해서 처음에 헤맸다. 어느정도 였냐면 가상환경 만들고 켜는 법도 몰라서 팀원들한테 물어봄... 어이없다. 진짜. 파이참 짱.

 

멋사 들어와서 가장 해보고 싶었던 첫 해커톤. 완료! 수고했다!

 

 

 

'멋쟁이사자처럼 9기 > 미니 해커톤' 카테고리의 다른 글

영화 평가 사이트 | 210724  (0) 2021.07.26
Comments