Курсовая / подсказка к 4 задачке

Чтобы сделать активное меню, надо сначала оценить какие страницы в навигации у вас есть

Делаем динамическую навигацию

Например, у меня в _navigation.html

<a href="/">Главная</a>
<a href="/about">Обо мне</a>
<a href="/best_page">Самая лучшая страница</a>
<hr>

то есть у нас получается 3 ссылки, которые можно выписать в табличку, вот так:

Название URL
Главная /
Обо мне /about
Самая лучшая страница /best_page

в python это можно представить в виде списка словариков. То есть мы считаем одну строку как словарик вида

{
   "title": "Главная", "URL": "/"
}

и тогда весь список можно записать следующим образом

[
    { "title": "Главная", "URL": "/" },
    { "title": "Обо мне", "URL": "/about" },
    { "title": "Самая лучшая страница", "URL": "/best_page" },
]

теперь пойдем в файлик сервера server.py, который у меня выглядит так

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def hello_world():
    return render_template("index.html", name="Главная")

@app.route("/about")
def about_view():
    return render_template("about.html", name="Обо мне")

@app.route("/best_page")
def best_page_view():
    return render_template("best_page.html", name="Самая лучшая страница")    

и добавим в самый верх переменную под навигацию

from flask import Flask, render_template

app = Flask(__name__)

nav = [
    { "title": "Главная", "URL": "/" },
    { "title": "Обо мне", "URL": "/about" },
    { "title": "Самая лучшая страница", "URL": "/best_page" },
]

# ... ОСТАЛЬНОЕ НЕ ТРОГАЕМ

теперь когда у нас есть такая переменная, ее можно передать в рендеринг шаблонов

после того как переменная попала в шаблон мы можем там ее попробовать вывести, добавим в _navigation.html

<!-- ДОБАВИЛ -->
<pre>
{{nav}}
</pre>
<!-- конец ДОБАВИЛ -->

<a href="/">Главная</a>
<a href="/about">Обо мне</a>
<a href="/best_page">Самая лучшая страница</a>
<hr>

получится так:

на же понятное хочется генерировать разметку. Так что давайте создадим цикл:

то есть я вывожу каждый пункт меню и ставлю после него тег br, чтобы оно выводилось в столбик

сгенерированная разметка выглядит вот так

синий – это то, что было {{ item }} а красное – это собстенно тег <br>

то есть, видите, он на каждый элемент навигации добавил одну строчку. Так как мы хотим генерировать ссылки мы можем повыковыривать отдельные значения словарика каждого элемента.

Например, можно вывести только имена:

или добавить к ним ссылки:

ну а вообще логичнее всего сделать прям тег <a> с значениями из item

вот так получится

то есть в принципе можно теперь убрать менюшку, которую вы вручную писали

получится как в самом начале, только теперь меню динамическое

Подсвечиваем активный элемент меню

Чтобы было понятно на какой странице хорошей практикой считается подсвечивать активный элемент меню.

Давайте добавим класс для активного элемента

добавим его в цикле в тег a

получится вот так

то есть все стали активными. Если глянуть сгенерированный код (Ctrl+U) то увидим

Для того чтобы актвиным был только один элемент надо добавить условие. В шаблонизаторе тоже можно использовать if выглядит это так

работает по принципу, когда item.title совпадет с name текущей страницы и если они совпадают, то выводим class="active"

проверим как работает:

красота! =)

Оптимизируем передачу данных

Если так глянуть у нас навигация присутствует на каждой странице. И вот получается, что передавать вот этот nav=nav в каждый вызов render_template немного лениво, да и в принципе идет в разрез с DRY (dont repeat yourself) подходом.

Во Flask есть возможность объявить так называемый глобальный контекст шаблона и передать туда переменные, которые должны быть доступны на каждой странице.

Делается это путем добавления специальной функции, которая возвращает глобальные переменные в виде словарика. Вот так:

проверяем:

Работает так же =О

Делаем навигацию на bootstrap

Идем на сайт bootstrap в компоненту навигации

https://getbootstrap.com/docs/5.2/components/navbar/#nav

и копипастим оттуда:

<nav class="navbar navbar-expand-lg bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Features</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Pricing</a>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled">Disabled</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

вставляем в навигацию

получится так

если присмотреться, то заметим, что за ссылки отвечают вот эти штуковины

по сути один пункт имеет вид

<li class="nav-item">
    <a class="nav-link active" aria-current="page" href="#">Home</a>
</li>

то есть давайте вместо четырех ссылок сделаем цикл, который генерит такую конструкцию вот так

получится

подставим значения item.URL и item.title

проверим:

у нас кнопки все активны потому что всегда стоит класс active

давайте тоже будем его генерить динамически

тестируем:

Отлично! =)

ну и можно убрать теперь старую навигацию

<nav class="navbar navbar-expand-lg bg-light">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">Navbar</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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">
          {% for item in nav %}
            <li class="nav-item">
              <a class="nav-link {% if item.title == name %}active{% endif %}" aria-current="page" href="{{ item.URL }}">{{ item.title }}</a>
            </li>
          {% endfor %}
        </ul>
      </div>
    </div>
  </nav>
<hr>

<style>
    .active {
        background-color: yellow;
    }
</style>

о как получится

4

Создаем активное меню