회원가입

[리팩토링] 12. (3) board 함수 리팩토링 전체 게시판 View 재구성

Beany 2024-06-30

  AS-IS Code

def get_board_set_from_board_group(request, board_group_id):
    ...완료!!!

def home(request):
    ...완료!!!

def board(request, board_url):
    ...이번장!!!

def post_detail(request, board_url, pk):
    ...

def reply_write(request, board_url, pk):
    ...

def rereply_write(request, board_url, pk):
    ...

def reply_delete(request, board_url, pk):
    ...

def rereply_delete(request, board_url, pk):
    ...

def like(request, board_url, pk):
    ...

[ get_board_set_from_board_group 함수 리팩토링 ]
get_board_set_from_board_group 리팩토링 정보 보기

[ home 함수 리팩토링 ]
home 페이지 성능 개선 Board View 코드 리팩토링
home 페이지 좋아요, 댓글 수 Board View 코드 리팩토링

Board 앱의 View 함수들을 살펴보니 총 9개의 코드가 존재합니다.
하나하나씩 불필요한 코드를 제거하거나 리팩토링해 보겠습니다


 

전체 검색 게시판에 대한 로직을 새로운 endpoint 로 재구성

엔드포인트를 재구성하기 위해 일반 게시판, 검색 게시판, 태그 게시판에서 공용으로 사용되는 함수를 Service Layer로 분리하여 각각의 새로운 View에서 해당 로직을 사용할 수 있도록 코드 작업을 했습니다..

이제 전체 검색 게시판을 위한 endpoint 분리를 해보겠습니다.

 

from django.urls import path
from .views import *

app_name = 'board'

urlpatterns = [
    path('board', get_all_boards, name='all_board_posts'),
    path('board/tag/<str:tag_name>', get_tagged_posts, name='get_tagged_posts'),
    path('board/<str:board_url>', get_board_posts, name='get_board_posts'),
    ...
]

위의 path('board', get_all_board_posts, name='all_board_posts') 와 같이 하나의 새로운 endpoint 를 만드려고 합니다.

get_board_posts View 안에 있는 코드를 리펙토링해서, 작업하려고 합니다.

 

지금 get_board_posts 의 문제점은 View Layer라는 점입니다.
즉, path('board', get_all_board_posts, name='all_board_posts') 에서 get_all_board_posts를 사용하려면 공통적인 부분을 Service Layer로 이용해야 한다는 점입니다.

def get_board_posts(request, board_url):
    board_detail = get_object_or_404(Board, url=board_url)

    board_posts_request = BoardPostsRequest.of(request)

    paging_data = web_paging(
        get_active_filtered_posts(
            search=board_posts_request.search,
            board_urls=[board_url],
        ).select_related(
            'author'
        ).order_by(
            '-id'
        ),
        int(request.GET.get('page', 1)),
        10,
        5,
    )
    page_posts = paging_data['page_posts']
    has_previous = page_posts.has_previous()
    has_next = page_posts.has_next()
    return render(
        request,
        'board/board_detail.html',
        BoardPostsResponse(
            board_detail_info=BoardDetailInfo(
                name=board_detail.name,
                info=board_detail.info,
                url=board_detail.url,
                board_img_url=board_detail.board_img.url if board_detail.board_img else None,
                name_background_color=board_detail.name_background_color,
                name_text_color=board_detail.name_text_color,
                info_background_color=board_detail.info_background_color,
                info_text_color=board_detail.info_text_color,
            ),
            posts=[
                BoardPost(
                    id=post.id,
                    title=post.title,
                    short_body=post.short_body(),
                    board_url=post.board.url,
                    author_nickname=post.author.nickname,
                    created_at=post.created_at.strftime('%Y-%m-%d'),
                    like_count=post.like_count,
                    reply_count=post.reply_count,
                    image_url=post.post_img.url if post.post_img else static('logo.ico'),
                ) for post in page_posts
            ],
            has_previous=has_previous,
            has_next=has_next,
            previous_page_number=page_posts.previous_page_number() if has_previous else None,
            current_page_number=page_posts.number,
            next_page_number=page_posts.next_page_number() if has_next else None,
            last_page_number=page_posts.paginator.num_pages,
            page_range=paging_data['page_range'],
        ).model_dump()
    )

 

리펙토링을 해봅시다.

Service Layer 에 함수를 새로 생성합니다.

def get_board_paged_posts(search: str = None, page: Union[int, str] = 1, board_urls: List[str] = None, tag_names: List[str] = None):
    paging_data = web_paging(
        get_active_filtered_posts(
            search=search,
            board_urls=board_urls,
            tag_names=tag_names,
        ).select_related(
            'author'
        ).order_by(
            '-id'
        ),
        int(page),
        10,
        5,
    )
    return paging_data

 

그리고 이 함수로 기존의 코드들을 리펙토링합니다.

def get_board_posts(request, board_url):
    board_detail = get_object_or_404(Board, url=board_url)

    board_posts_request = BoardPostsRequest.of(request)

    paging_data = get_board_paged_posts(
        search=board_posts_request.search,
        board_urls=[board_url],
        page=request.GET.get('page', 1)
    )
    page_posts = paging_data['page_posts']
    has_previous = page_posts.has_previous()
    has_next = page_posts.has_next()
    return render(
        ...
    )

 

이제 get_all_board_posts 를 만들어 봅시다.

def get_all_board_posts(request):
    board_posts_request = BoardPostsRequest.of(request)
    board_detail_display = '전체 게시판'
    if board_posts_request.search:
        board_detail_display = board_posts_request.search

    paging_data = get_board_paged_posts(
        search=board_posts_request.search,
        page=request.GET.get('page', 1)
    )
    page_posts = paging_data['page_posts']
    has_previous = page_posts.has_previous()
    has_next = page_posts.has_next()
    return render(
        request,
        'board/all_board_detail.html',
        BoardPostsResponse(
            board_detail_info=BoardDetailInfo(
                name=board_detail_display,
                info=board_detail_display,
                url=board_detail_display,
            ),
            posts=[
                BoardPost(
                    id=post.id,
                    title=post.title,
                    short_body=post.short_body(),
                    board_url=post.board.url,
                    author_nickname=post.author.nickname,
                    created_at=post.created_at.strftime('%Y-%m-%d'),
                    like_count=post.like_count,
                    reply_count=post.reply_count,
                    image_url=post.post_img.url if post.post_img else static('logo.ico'),
                ) for post in page_posts
            ],
            has_previous=has_previous,
            has_next=has_next,
            previous_page_number=page_posts.previous_page_number() if has_previous else None,
            current_page_number=page_posts.number,
            next_page_number=page_posts.next_page_number() if has_next else None,
            last_page_number=page_posts.paginator.num_pages,
            page_range=paging_data['page_range'],
        ).model_dump()
    )

HTML

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

{% block style %}
<style>
.card_img{
    background-repeat:no-repeat;
    background-position-y:center;
    background-size:contain;
}
.truncate-3 {
    font-size: 15px;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}
</style>
{% endblock %}

{% block title %}{{board_detail_info.name}}{% endblock %}
{% block og_title %}{{board_detail_info.name}}{% endblock %}
{% block description %}{{board_detail_info.info}}{% endblock %}
{% block current_url %}https://cwbeany.com{{ request.get_full_path }}{% endblock %}
{% block img %}https://cwbeany.com/static/logo.ico{% endblock %}

{% block top %}
<div class="p-4 p-md-5 mb-3 rounded">
    <div class="col-md-8 px-0">
        <h3 class="display-4 font-monospace">{{board_detail_info.name}}</h3>
        <p class="lead my-3 font-monospace">WHAT WE FOUND "{{ board_detail_info.name }}" LIST</p>
    </div>
</div>
<!-- 글 목록 -->
<div class="row g-2 mb-4">
    {% for post in posts %}
    <div class="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
        <a class="text-decoration-none text-dark" href="{% url 'board:post' post.board_url post.id %}">
            <div class="card">
                <div class="row g-0">
                    <div class="col-lg-8">
                        <div class="card-body">
                            <h5 class="card-title" style="white-space:nowrap;overflow: hidden;text-overflow:ellipsis;">{{post.title}}</h5>
                            <p class="card-text truncate-3">{{post.short_body|striptags}}</p>
                            <div class="card-text"><small class="text-muted"><i class="bi bi-person-circle"></i> {{post.author_nickname}}</small></div>
                            <div class="card-text"><small class="text-muted"><i class="bi bi-calendar-week"></i> {{post.created_at}}</small></div>
                            <div>
                                <i class="bi bi-heart text-danger"></i></i> {{post.like_count}} <i class="bi bi-chat-right-text"></i> {{post.reply_count}}
                            </div>
                        </div>
                    </div>
                    <div class="col-lg-4 card_img d-none d-lg-block rounded" style="background-image:url({{post.image_url}});">
                    </div>
                </div>
            </div>
        </a>
    </div>
    {% endfor %}
</div>
<!-- 검색 하기 -->
<form class="d-flex mb-3" style="justify-content: flex-end;" method="get" action="">
    <input class="me-2" type="text" value="{{ request.GET.search }}" name="search" placeholder="검색어를 입력하세요." />
    <button class="btn btn-sm btn-primary" type="submit">검색</button>
</form>

<!-- 페이지 네이션 -->
<nav aria-label="Page navigation example">
    <ul class="pagination justify-content-center">
        {% if has_previous %}
        <li class="page-item">
            {% if request.GET.search %}
                <a class="page-link" href="?page=1&search={{ request.GET.search }}" aria-label="First">
                    <span aria-hidden="true">&laquo;</span>
                </a>
            {% else %}
                <a class="page-link" href="?page=1" aria-label="First">
                    <span aria-hidden="true">&laquo;</span>
                </a>
            {% endif %}
        </li>
        <li class="page-item">
            {% if request.GET.search %}
                <a class="page-link" href="?page={{ previous_page_number }}&search={{ request.GET.search }}" aria-label="Previous">
                    <span aria-hidden="true">&lt;</span>
                </a>
            {% else %}
                <a class="page-link" href="?page={{ previous_page_number }}" aria-label="Previous">
                    <span aria-hidden="true">&lt;</span>
                </a>
            {% endif %}
        </li>
        {%endif%}

        {% for i in page_range %}
            {% if i == current_page_number %}
                {% if request.GET.search %}
                    <li class="page-item active"><a class="page-link" href="?page={{i}}&search={{ request.GET.search }}">{{i}}</a></li>
                {% else %}
                    <li class="page-item active"><a class="page-link" href="?page={{i}}">{{i}}</a></li>
                {% endif %}
            {% else %}
                {% if "search=" in request.get_full_path %}
                    <li class="page-item"><a class="page-link" href="?page={{i}}&search={{ request.GET.search }}">{{i}}</a></li>
                {% else %}
                    <li class="page-item"><a class="page-link" href="?page={{i}}">{{i}}</a></li>
                {% endif %}
            {% endif %}
        {% endfor %}

        {% if has_next %}
        <li class="page-item">
        {% if request.GET.search %}
            <a class="page-link" href="?page={{ next_page_number }}&search={{ request.GET.search }}" aria-label="Next">
                <span aria-hidden="true">&gt;</span>
            </a>
        {% else %}
            <a class="page-link" href="?page={{ next_page_number }}" aria-label="Next">
                <span aria-hidden="true">&gt;</span>
            </a>
        {% endif %}
        </li>

        <li class="page-item">
        {% if request.GET.search %}
            <a class="page-link" href="?page={{ last_page_number }}&search={{ request.GET.search }}" aria-label="Last">
                <span aria-hidden="true">&raquo;</span>
            </a>
        {% else %}
            <a class="page-link" href="?page={{ last_page_number }}" aria-label="Last">
                <span aria-hidden="true">&raquo;</span>
            </a>
        {% endif %}
        </li>
        {%endif%}
    </ul>
</nav>
{% endblock %}

짠~ 완성되었습니다!!

 

 

이제 검색할 때, 이 게시판으로 옮기도록 기존 코드를 바꿔야합니다.

board/templates/board/home.html

board:all_board_posts 로 바꿔줍니다..

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

{% block style %}
...
{% endblock %}

{% block middle_right %}
<!-- 검색 하기 -->
<form class="d-flex mb-3" style="justify-content: flex-end;" method="get" action="{% url 'board:all_board_posts' %}">
    <input class="me-2" type="text" value="{{ request.GET.search }}" name="search" placeholder="검색어를 입력하세요." />
    <button class="btn btn-sm btn-primary" type="submit">검색</button>
</form>

<!-- 소개 -->
...

<!-- Announce -->
...

<!-- Tags -->
...
{% endblock %}

 

검색을 하니 잘 이동합니다.

0 0
블로그 일기
제 블로그의 고도화 과정을 설명합니다. 이는 코드 리팩토링과 추가된 기능들에 대해 기록하기 위한 게시판입니다. 어떤 기능이 추가되었는지, 무엇이 개선되었는지 등 고도화되는 과정을 자세히 다룰 예정입니다.
Yesterday: 456
Today: 125