Продвинутый Django 5 для продолжающих

Прогресс по курсу:  0/193

6.6 Добавление в проект Bootstrap 5
4 из 4 шагов пройдено

Добавление в проект Bootstrap 5


Подключим Bootstrap 5 и добавим его классы в шаблон templates\base.html:

{% load static %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{% block title %}Books{% endblock title %}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
    <link rel="stylesheet" href="{% static 'base.css' %}">
</head>

<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>

<div class="container">
    <div class="row">
        <div class="col">
            <!-- Форма для добавления новой книги -->
            {% include "partial_create_book_form.html" %}

            <!-- Таблица книг -->
            <form class="form-inline">
                <table class="table table-bordered table-sm mt-5">
                    <thead>
                    <tr>
                        <!-- Заголовки столбцов таблицы -->

                        <!-- Заголовок номера книги -->
                        <th scope="col" style="width: 10%" class="text-center">
                            <small>
                                No.
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='id' direction='ascend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='id' direction='descend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                            </small>
                        </th>

                        <!-- Заголовок названия книги -->
                        <th scope="col" style="width: 26%" class="text-center">
                            <small>
                                Title
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='title' direction='ascend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='title' direction='descend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                            </small>
                        </th>

                        <!-- Заголовок автора книги -->
                        <th scope="col" style="width: 26%" class="text-center">
                            <small>
                                Author
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='author' direction='ascend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='author' direction='descend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                            </small>
                        </th>

                        <!-- Заголовок цены книги -->
                        <th scope="col" style="width: 11%" class="text-center">
                            <small>
                                Price ($)
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='price' direction='ascend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='price' direction='descend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                            </small>
                        </th>

                        <!-- Заголовок статуса книги -->
                        <th scope="col" style="width: 11%" class="text-center">
                            <small>
                                Status
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='read' direction='descend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                                <a href=""
                                   hx-get="{% url 'book_list_sort' filter='read' direction='ascend' %}"
                                   hx-target="#book-list"
                                   hx-swap="innerHTML"></a>
                            </small>
                        </th>

                        <!-- Заголовок кнопок действия -->
                        <th scope="col" style="width: 16%" class="text-center">
                            <small>
                                Actions
                            </small>
                        </th>

                    </tr>
                    </thead>

                    <!-- Список книг -->
                    <tbody id="book-list">
                    {% include "partial_book_list.html" %}
                    </tbody>

                </table>
            </form>
        </div>
    </div>
</div>

<script src="https://unpkg.com/htmx.org@1.9.4"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
        crossorigin="anonymous"></script>

<script>
    function cngElementsAtr(cls, atr, val) {
        var elems = document.getElementsByClassName(cls);
        for (var i = 0; i < elems.length; i++) {
            elems[i][atr] = val;
        }
    }

    document.body.addEventListener('htmx:afterRequest', (event) => {
        path_str = event.detail.pathInfo.requestPath;
        if (path_str.includes('create_book')) {
            cngElementsAtr('clrtxt', 'value', '');
        } else if (path_str.includes('update_book_details')) {
            if (event.detail.requestConfig.verb === 'put') {
                cngElementsAtr('disbtn', 'disabled', true);
            } else {
                cngElementsAtr('disbtn', 'disabled', false);
            }
        } else if (path_str.includes('book_detail')) {
            cngElementsAtr('disbtn', 'disabled', false);
        }
    });
</script>
</body>
</html>


Добавим Bootstrap-классы в шаблон templates\partial_book_detail.html:

<tr class="{% if book.read %}grey-text{% endif %}">
    <!-- Ячейка номера книги -->
    <td class="align-middle text-center ps-2">
        {{ book.id }}
    </td>

    <!-- Ячейка названия книги -->
    <td class="align-middle ps-2">
        {{ book.title }}
    </td>

    <!-- Ячейка автора книги -->
    <td class="align-middle ps-2">
        {{ book.author }}
    </td>

    <!-- Ячейка цены книги -->
    <td class="align-middle text-center">
        {{ book.price }}
    </td>

    <!-- Ячейка состояния -->
    <td class="align-middle text-center">
        {% if not book.read %}
            <!-- Кнопка "Unread" -->
            <button class="disbtn table-button status-button btn btn-primary btn-sm"
                    hx-put="{% url 'update_book_status' book.id %}"
                    hx-target="closest tr"
                    hx-swap="outerHTML">
                Unread
            </button>
        {% else %}
            <!-- Кнопка "Read" -->
            <button class="disbtn table-button status-button btn btn-secondary btn-sm"
                    hx-put="{% url 'update_book_status' book.id %}"
                    hx-target="closest tr"
                    hx-swap="outerHTML">
                Read
            </button>
        {% endif %}
    </td>

    <!--  Ячейка кнопок действия -->
    <td class="align-middle text-center">
        <!-- Кнопка "Edit" -->
        <button class="disbtn table-button any-button btn btn-primary btn-sm me-2"
                hx-put="{% url 'update_book_details' book.id %}"
                hx-target="closest tr"
                hx-swap="outerHTML">
            Edit
        </button>

        <!-- Кнопка "Delete" -->
        <button class="disbtn table-button any-button btn btn-danger btn-sm"
                hx-delete="{% url 'delete_book' book.id %}"
                hx-target="closest tr"
                hx-swap="outerHTML"
                hx-confirm="Are you sure you wish to delete this book?">
            Delete
        </button>
    </td>
</tr>


Добавим Bootstrap-классы в шаблон templates\partial_book_update_form.html:

<tr class="{% if book.read %}grey-text{% endif %}">
    <!-- Ячейка номера книги -->
    <td class="align-middle text-center ps-2">
        {{ book.id }}
    </td>

    <!-- Ячейка названия книги -->
    <td class="align-middle ps-2">
        {{ form.title }}
    </td>

    <!-- Ячейка автора книги -->
    <td class="align-middle ps-2">
        {{ form.author }}
    </td>

    <!-- Ячейка цены книги -->
    <td class="align-middle text-center">
        {{ form.price }}
    </td>

    <!-- Ячейка состояния -->
    <td class="align-middle text-center">
        {% if not book.read %}
            <!-- Кнопка "Unread" -->
            <button class="table-button status-button btn btn-primary btn-sm" disabled>
                Unread
            </button>
        {% else %}
            <!-- Кнопка "Read" -->
            <button class="table-button status-button btn btn-secondary btn-sm" disabled>
                Read
            </button>
        {% endif %}
    </td>

    <!--  Ячейка кнопок действия -->
    <td class="align-middle text-center">
        <!-- Кнопка "Save" -->
        <button type="submit"
                class="table-button any-button btn btn-success btn-sm me-2"
                hx-post="{% url 'update_book_details' book.id %}"
                hx-target="closest tr"
                hx-swap="outerHTML"
                hx-include="closest tr">
            Save
        </button>
        <!-- Кнопка "Cancel" -->
        <button class="table-button any-button btn btn-warning btn-sm"
                hx-get="{% url 'book_detail' book.id %}"
                hx-target="closest tr"
                hx-swap="outerHTML">
            Cancel
        </button>
    </td>
</tr>


Добавим Bootstrap-классы в шаблон templates\partial_create_book_form.html:

<form class="form-inline">
    <div class="row">
        <div class="col">
            {{ form.title }}
        </div>

        <div class="col">
            {{ form.author }}
        </div>

        <div class="col">
            {{ form.price }}
        </div>

        <div class="col">
            <!-- Кнопка "Add book" -->
            <button type="submit"
                    class="disbtn btn btn-primary"
                    hx-post="{% url 'create_book' %}"
                    hx-target="#book-list"
                    hx-swap="beforeend">
                Add book
            </button>
        </div>
    </div>
</form>


Добавим Bootstrap-класс form-control в файл books\forms.py:

class BookEditForm(BookCreateForm):
    title  = CharField(required=False, widget=TextInput(attrs={"class":"form-control-sm form-control"}))
    author = CharField(required=False, widget=TextInput(attrs={"class":"form-control-sm form-control"}))
    price  = CharField(required=False, widget=TextInput(attrs={"class":"form-control-sm form-control"}))

Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий
Нет обсуждений. Начните первое.