Django/inflearn

Join으로 모든 리뷰 리스트 불러오기

곽수진 2022. 12. 7. 23:59
반응형

from django.shortcuts import render, get_object_or_404, redirect
from third.models import Restaurant, Reviews
from django.core.paginator import Paginator
from third.forms import RestaurantForm, ReviewForm
from django.http import HttpResponseRedirect

# Create your views here.
def list(request):
    restaurants = Restaurant.objects.all()
    paginator = Paginator(restaurants, 5)

    page = request.GET.get('page')
    items = paginator.get_page(page)

    context = {
        'restaurants': items
    }
    return render(request, 'third/list.html', context)


def create(request):
    if request.method == 'POST':
        form = RestaurantForm(request.POST)
        if form.is_valid():
            new_item = form.save()
        return HttpResponseRedirect('/third/list/')
    form = RestaurantForm()
    return render(request, 'third/create.html', {'form': form})


def update(request):
    if request.method == 'POST' and 'id' in request.POST:
        # item = Restaurant.objects.get(pk=request.POST.get('id'))
        item = get_object_or_404(Restaurant, pk=request.POST.get('id'))
        form = RestaurantForm(request.POST, instance=item)
        if form.is_valid():
            item = form.save()
    elif request.method == 'GET':
        # item = Restaurant.objects.get(pk=request.GET.get('id'))
        item = get_object_or_404(Restaurant, pk=request.GET.get('id'))
        form = RestaurantForm(instance=item)
        return render(request, 'third/update.html', {'form': form})
    return HttpResponseRedirect('/third/list/')


def detail(request, id):
    if 'id' is not None:
        item = get_object_or_404(Restaurant, pk=id)
        reviews = Reviews.objects.filter(restaurant=item).all()
        return render(request, 'third/detail.html', {'item': item, 'reviews': reviews})
    return HttpResponseRedirect('/third/list/')


def delete(request):
    if 'id' in request.GET:
        item = get_object_or_404(Restaurant, pk=request.GET.get('id'))
        item.delete()
    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()
        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(Reviews, pk=review_id)
    item.delete()

    return redirect('restaurant-detail', id=restaurant_id)


def review_list(request):
    reviews = Reviews.objects.all().order_by('-created_at')
    paginator = Paginator(reviews, 10)

    page = request.GET.get('page')
    items = paginator.get_page(page)

    context = {
        'reviews': items
    }
    return render(request, 'third/review_list.html', context)

paginator = Paginator(reviews, 10) : 한 페이지에 10개씩 표시

page = request.GET.get('page') : query params에서 page 데이터를 가져옴

items = paginator.get_page(page) : 해당 페이지의 아이템으로 필터링

 

 

{% extends 'third/base.html' %}
{% load static %}
{% block content %}
<div class="container">
    {% for item in reviews %}
    <div class="row restaurant-item" style="margin:20px auto">
        <div class="card border-secondary">
            <div class="card-body">
                <h5 class="card-title">{{ item.restaurant.name }}</h5>
                <h6 class="card-subtitle mb-2 text-muted">{{ item.restaurant.address }}</h6>
                <p class="card-text">{{ item.point }}점 / {{ item.comment }}</p>
            </div>
        </div>
    </div>
    {% endfor %}

    <div class="row">
        <div class="col-sm-12 text-center">
            <div class="pagination">
                <span class="step-links text-center" style="width:100%;">
                    {% if reviews.has_previous %}
                        <a href="?page=1">&laquo;</a>
                        <a href="?page={{ reviews.previous_page_number }}">{{ reviews.previous_page_number }}</a>
                    {% endif %}
                    <span class="current">
                        {{ reviews.number }}
                    </span>
                    {% if reviews.has_next and reviews.next_page_number != reviews.paginator.num_pages %}
                        <a href="?page={{ reviews.next_page_number }}">{{ reviews.next_page_number }}</a>
                        <a href="?page={{ reviews.paginator.num_pages }}">{{ reviews.paginator.num_pages }}</a>
                    {% elif reviews.has_next and reviews.next_page_number == reviews.paginator.num_pages %}
                        <a href="?page={{ reviews.next_page_number }}">{{ reviews.next_page_number }}</a>
                    {% endif %}
                </span>
            </div>
        </div>
    </div>
</div>
{% endblock %}

▶ 리뷰 목록을 가져올 review_list.html 파일 생성

{{ item.restaurant.(Restaurant 모델에 정의된 속성) }} : Review와 Restaurant의 relation이 models.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('detail/', views.detail, name="restaurant-detail"),
    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"),
    path('review/list', views.review_list, name="review-list")
]

▶ urls.py 파일에 review_list 화면을 연결

 

 

{% load static %}
<html>
<head>
    <meta charset="UTF-8">
    <title>음식점</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link rel="stylesheet" href="{% static 'third/styles.css' %}">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.3/dist/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <a class="navbar-brand" href="/third/list">음식점</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
          <li class="nav-item">
            <a class="nav-link" href="/third/list">리스트</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="/third/create">등록</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="/third/review/list">리뷰 리스트</a>
          </li>
        </ul>
      </div>
    </nav>
  {% block content %}
  {% endblock %}
</body>
</html>

▶ 기존에 있던 base.html 파일에 리뷰 리스트 링크 추가

 

 

list 화면

 

 

review list 화면

 

 

다른 게시글에 리뷰를 추가적으로 작성

 

 

다시 review list 확인

 

 

from django.shortcuts import render, get_object_or_404, redirect
from third.models import Restaurant, Reviews
from django.core.paginator import Paginator
from third.forms import RestaurantForm, ReviewForm
from django.http import HttpResponseRedirect

# Create your views here.
def list(request):
    restaurants = Restaurant.objects.all()
    paginator = Paginator(restaurants, 5)

    page = request.GET.get('page')
    items = paginator.get_page(page)

    context = {
        'restaurants': items
    }
    return render(request, 'third/list.html', context)


def create(request):
    if request.method == 'POST':
        form = RestaurantForm(request.POST)
        if form.is_valid():
            new_item = form.save()
        return HttpResponseRedirect('/third/list/')
    form = RestaurantForm()
    return render(request, 'third/create.html', {'form': form})


def update(request):
    if request.method == 'POST' and 'id' in request.POST:
        # item = Restaurant.objects.get(pk=request.POST.get('id'))
        item = get_object_or_404(Restaurant, pk=request.POST.get('id'))
        form = RestaurantForm(request.POST, instance=item)
        if form.is_valid():
            item = form.save()
    elif request.method == 'GET':
        # item = Restaurant.objects.get(pk=request.GET.get('id'))
        item = get_object_or_404(Restaurant, pk=request.GET.get('id'))
        form = RestaurantForm(instance=item)
        return render(request, 'third/update.html', {'form': form})
    return HttpResponseRedirect('/third/list/')


def detail(request, id):
    if 'id' is not None:
        item = get_object_or_404(Restaurant, pk=id)
        reviews = Reviews.objects.filter(restaurant=item).all()
        return render(request, 'third/detail.html', {'item': item, 'reviews': reviews})
    return HttpResponseRedirect('/third/list/')


def delete(request):
    if 'id' in request.GET:
        item = get_object_or_404(Restaurant, pk=request.GET.get('id'))
        item.delete()
    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()
        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(Reviews, pk=review_id)
    item.delete()

    return redirect('restaurant-detail', id=restaurant_id)


def review_list(request):
    reviews = Reviews.objects.all().select_related().order_by('-created_at')
    paginator = Paginator(reviews, 10)

    page = request.GET.get('page')
    items = paginator.get_page(page)

    context = {
        'reviews': items
    }
    return render(request, 'third/review_list.html', context)

review 조회 시에 바로 join을 사용해서 restaurant 가져오기

▶ 기존에 구현했던 방식은 실제로 join을 하지 않기 때문에 item.restaurnat을 호출할 때마다 연관된 음식점 데이터를 조회하는 쿼리문이 리뷰의 개수만큼 수행되어 사이트가 느려질 수 있음

▶ Django ORM에서 데이터를 조회할 때 .select_related() 메소드를 추가로 호출하면 됨

반응형