Flask + Bootstrap nav, 선택 메뉴 표시하기

배경

Python, Flask, Bootstrap을 이용하여 웹사이트 하나를 거의 완성했다. 버전 1.0을 찍고 끝내도 될 것 같다. 마무리로 상단 메뉴를 클릭하면 선택한 메뉴를 표시해 주려고 한다. 상단 메뉴는 Bootstrap nav를 사용했는데, 예제를 보니 class에 active를 지정하기만 하면 된다.  


1차 시도

자바스크립트를 쓰면 된다고 생각했다. 특정 메뉴를 클릭하면 그 이벤트를 받아서 class에 active를 추가해주면 되겠지? 그러나 완벽한 착각이었다. 메뉴를 선택하면 서버에 페이지를 요청해서 다시 받아 오는데, 될 리가 없지. 지금 생각하면 어이가 없는데, 그 때는 왜 그렇게 쉽게 생각했을까? 


2차 시도

검색을 해봤다. 서버에서 특정 메뉴에 대한 응답을 줄 때 각 메뉴마다 유니크한 변수의 값으로 active를 주고, 메뉴 페이지에서 특정 메뉴마다 유니크한 변수를 호출해서 active를 출력하는 방법을 찾았다.  

@bp.route('/page_1/')
def view_page_1():
    page_1_active = 'active'
    return render_template('page_1.html', page_1_active=page_1_active)
 
    
@bp.route('/page_2/')
def view_page_2():
    page_2_active = 'active'
    return render_template('page_2.html', page_2_active=page_2_active)
cs


<ul class="nav nav-pills">
    <li class="nav-item">
        <a class="nav-link {{ page_1_active }}" href="{{ url_for('view_page_1') }}">page_1</a>
    </li>
    <li class="nav-item">
        <a class="nav-link {{ page_2_active }}" href="{{ url_for('view_page_2') }}">page_2</a>
    </li>
</ul>
cs

이걸 적용하려면 관련 메서드 마다 각기 다른 변수를 만들어서 응답해주는 코드를 일일이 추가해야 한다. 최선일까? 파이썬 메소드마다 처리해야 할 본래의 로직에 추가로 페이지 처리를 위한 로직을 추가하는 건 좋은 생각이 아닌 것 같다. 흔히 말하는 나쁜 냄새가 난다. 


3차 시도

몇 가지 방법을 더 찾았고, html 페이지에서 request.path를 이용해서 처리하는 것으로 결정했다. 이렇게 하면 파이썬 메서드는 건드릴 필요가 없다. 메뉴를 처리하는 html 페이지만 아래처럼 작성해 주면 된다. 

<ul class="nav nav-pills">
    <li class="nav-item">
        <a class="nav-link {% if request.path == url_for('view_page_1') %}active{% endif %}" href="{{ url_for('view_page_1') }}">page_1</a>
    </li>
    <li class="nav-item">
        <a class="nav-link {% if request.path == url_for('view_page_2') %}active{% endif %}" href="{{ url_for('view_page_2') }}">page_1</a>
    </li>
</ul>
cs

여기서 request는 flask.Request 클래스의 인스턴스이며, 멀티스레드 환경에서도 정확히 동작하는 글로벌 객체이다. path는 애플리케이션 내부에서 라우팅 되는 경로이다. 예를 들어 아래 조건이 True 라면, request.path의 값은 /page_1/ 이다. 

request.path == url_for('menu.page_1')

참고: flask.Request


댓글 쓰기

0 댓글