파이썬으로 장고(Django) 공략하기: 입문 강의를 정리한 내용입니다.
리뷰 등록, 삭제
- 리뷰 등록 폼을 나타낼 모델 폼을 작성한다.
# third/forms.py
from django import forms
from . models import Restaurant, Review
# 평점의 선택지
REVIEW_POINT_CHOICES = (
('1', 1),
('2', 2),
('3', 3),
('4', 4),
('5', 5),
)
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['point', 'comment', 'restaurant']
labels = {
'point': _('평점'),
'comment': _('코멘트'),
}
widgets = {
'restaurant': forms.HiddenInput(), # 리뷰를 달 식당 정보는 사용자에게 보여지지 않도록 한다
'point': forms.Select(choices=REVIEW_POINT_CHOICES) # 선택지를 인자로 전달
}
help_texts = {
'point': _('평점을 입력해주세요.'),
'comment': _('코멘트를 입력해주세요.'),
}
- 식당 상세화면 메소드에서 리뷰 목록을 조회하도록 수정하고 리뷰를 등록하는 view 메소드와 리뷰를 삭제하는 view 메소드를 추가한다.
- HttpResponseRedirect 대신 shortcuts의 redirect을 사용하여 코드를 줄일 수 있다.
# third/view.py
from django.shortcuts import render, get_object_or_404, redirect
from . models import Restaurant, Review
from . forms import RestaurantForm, ReviewForm
def detail(request, id): # 식당 조회 페이지
if 'id' is not None:
item = get_object_or_404(Restaurant, pk=id)
reviews = Review.objects.filter(restaurant=item).all() # 식당에 해당하는 리뷰을 조회
return render(request, 'third/detail.html', {'item': item, 'reviews': reviews})
return HttpResponseRedirect('/third/list/')
def review_create(request, restaurant_id):
if request.method == 'POST':
form = ReviewForm(request.POST)
if form.is_valid():
new_item = form.save()
# HttpResponseRedirect을 사용하면 url을 다 써주어야하고, 만약 url이 변경되었을 때 함께 수정해주어야 하는 번거로움이 있음
# shortcuts의 redirct를 사용하면 url 기반이 아니라 urls.py에 정의한 view name 기반으로 움직이기 때문에
# url이 변경되더라고 view name이 그대로라면 변경하지 않아도 된다.
return redirect('restaurant-detail', id=restaurant_id)
item = get_object_or_404(Restaurant, pk=restaurant_id)
form = ReviewForm(initial={'restaurant': item})
return render(request, 'third/review_create.html', {'form': form, 'item': item})
def review_delete(request, restaurant_id, review_id):
item = get_object_or_404(Review, pk=review_id)
item.delete()
return redirect('restaurant-detail', id=restaurant_id)
- url을 연결한다.
# third/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('list/', views.list, name="list"),
path('create/', views.create, name="restaurant-create"),
path('update/', views.update, name="restaurant-update"),
path('delete/', views.delete, name="restaurant-delete"),
path('restaurant/<int:id>/', views.detail, name="restaurant-detail"),
path('restaurant/<int:restaurant_id>/review/create/', views.review_create, name='review-create'),
path('restaurant/<int:restaurant_id>/review/delete/<int:review_id>', views.review_delete, name='review-delete')
]
- 리뷰 등록 템플릿을 추가한다.
<!-- third/templates/third/review_create.html -->
{% extends 'third/base.html' %}
{% load static %}
{% block content %}
<div class="container">
<form action="{% url 'review-create' restaurant_id=item.id %}" method="post" style="margin-top:20px;">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">등록</button>
</form>
</div>
{% endblock %}
- 식당 상세화면에 리뷰쓰기 링크와 리뷰 목록을 추가한다.
<!-- third/templates/third/detail.html -->
{% extends 'third/base.html' %}
{% load static %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-12" style="margin-top:20px;">
<h3>{{ item.name }}</h3>
<p>{{ item.address }}</p>
<p>
<a href="{% url 'restaurant-delete' %}?id={{ item.id }}">
<button class="btn btn-danger">삭제하기</button>
</a>
</p>
<hr>
<p>
<a href="{% url 'review-create' restaurant_id=item.id %}">
<button class="btn btn-info">리뷰쓰기</button>
</a>
</p>
{% for review in reviews %}
<div class="card bg-light mb-3">
<div class="card-header"><b>{{ review.point }}</b>점
<a href="{% url 'review-delete' restaurant_id=item.id review_id=review.id %}">
<button type="button" class="close" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</a>
</div>
<div class="card-body">
<p class="card-text">{{ review.comment }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}