3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер

3 горизонтальные линии, бургер
Удалить все
ЗАГРУЗКА ...

Содержание



    Как добавить форму обратной связи на Django/Python и HTMx

    Часы
    11.04.2025
    /
    Часы
    01.10.2025
    /
    Часы
    4 минуты
    Глазик
    578
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0

    Вступление

    В этой статье, я опишу как добавить на ваш Django-сайт форму обратной связи используя HTMx и немного DaisyUI, в качестве UI-библиотеки. Всё будет сделано на примере моего нового сайта (ссылки на который у меня пока нет, ибо он ещё в разработке). Но зато будут картинки ٩(◕‿◕。)۶

    Разберёмся с html и шаблонами

    Для начала, нужно выбрать место, где будет размещена форма. Это может быть отдельная страница, страница с контактами или же подвал сайта. Конкретно я, размещу его в подвале сайта, ибо так хочу. Вот как он будет выглядеть:
    Данная форма загружается у меня при помощи AJAX-запроса, то есть динамически, во время загрузки основной страницы. При помощи HTMx это можно сделать вот так:
    <nav class="flex flex-col gap-[5px]"> <h6 hx-get="feedback/" hx-trigger="load" hx-target="#feedback-form-container" hx-indicator="#simple_indicator" class="footer-title">{% trans 'Форма обратной связи' %}</h6> <div id="feedback-form-container"> <div id="simple_indicator" class="htmx-indicator">{% trans 'Loading ...' %}</div> </div> </nav>
    Здесь я делаю запрос на сервер(hx-get) по адресу feedback/, во время появления данного элемента в DOM(hx-tigger). Ответ сервера я вставляю в элемент div с id="feedback-form-container". Так же я указал простой индикатор загрузки при помощи атрибута hx-indicator, где указал его id.
    Заметь, я не использовал атрибут hx-swap, ибо у него есть значение по умолчанию, которое мне подходит, а именно "innerHTML"
    После запроса по адресу feedback/, сервер вернёт отрендереный шаблон, feedback-form.html.
    {% load i18n %} {% load static %} <form id="feedback-form" class="flex flex-col gap-[5px] min-w-[300px]"> {% csrf_token %} {% for field in form %} <div class="flex flex-row gap-[5px]"> {{ field }} </div> {% for error in field.errors %} <p class="m-[0] text-error">{{ error }}</p> {% endfor %} {% endfor %} <input hx-post="feedback/" hx-target="#feedback-form" hx-swap="outerHTML" class="btn btn-square btn-outline btn-error w-full" type="submit" value="{% trans 'Отправить' %}"> {% if success_feedback_message %} {% include 'parts/toast-message.html' with message=success_feedback_message status='success' %} {% endif %} {% if error_feedback_message %} {% include 'parts/toast-message.html' with message=error_feedback_message status='error' %} {% endif %} </form>
    Сервер вернёт контекстную переменную, form. Мы можем проитерировать её и получить все поля формы, а так же ошибки при заполнении, если таковые имеются. Плюс, мы отдельно вписываем кнопку отправки формы. И так как, наша цель для замены снипета кода, это сама форма, нужно ещё отдельно указать политику замены, то есть hx-swap=outerHTML.
    Вместе с формой вернётся сообщение с сервера о результате отправки формы. Это сообщение я отправляю в другой шаблон. Вот так я их подключаю и передаю:
    {% if success_feedback_message %} {% include 'parts/toast-message.html' with message=success_feedback_message status='success' %} {% endif %} {% if error_feedback_message %} {% include 'parts/toast-message.html' with message=error_feedback_message status='error' %} {% endif %}
    То как выглядит вернувшаяся форма с ошибками
    То как выглядит вернувшаяся форма без ошибок
    Шаблон сообщения с сервера(попап, тост), toast-message.html, выглядит вот так:
    <div id="toast_feedback" class="toast toast-bottom toast-end"> <div hx-get="api/raw_delete/" hx-target="#toast_feedback" hx-swap="outerHTML" hx-trigger="click, load delay:5s" class="alert alert-{{status}} flex flex-row gap-[5px]"> <div class="w-[20px] flex"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </div> <span>{{message}}</span> </div> </div>
    Чтобы корректно работать, данный шаблон должен принимать две контекстные переменные - сообщение(message) и его статус(status). Что более интересно в этом шаблоне, так это то, как и куда он отправляет запросы.
    Смотри, отправка запроса происходит при нажатии на сам попап или через 5 секунд после загрузки(hx-trigger="click, load delay:5s"). Запрос отправляется по адресу api/raw_delete/, в качестве ответа сервер всегда возвращает пустую строку и код ответа 200. Больше о триггерах в HTMx можно узнать здесь. А о кодах ответа тут.
    Вот представление на сервере, которое отвечает на GET-запросы по адресу api/raw_delete/:
    from django.http import HttpResponse from django.views.decorators.http import require_http_methods @require_http_methods(["GET"]) def raw_delete(request): return HttpResponse('', status=200)
    Не обязательно, конечно, использовать именно GET-запрос, просто он самый простой в разработке. Больше о декораторах на django-представления можно узнать уже здесь.
    По итогу, попап удаляется и пользователь снова может отправить запрос.

    Создадим специальную форму, FeedbackForm

    После того как были написаны шаблоны формы и попапы сообщений с сервера, можно и нужно написать класс формы, которая и определяет какие поля в ней должны присутствовать, какие являются обязательными, а какие нет.
    from django import forms from django.utils.translation import gettext_lazy as _ from captcha.fields import CaptchaField, CaptchaTextInput class FeedbackForm(forms.Form): username = forms.CharField( max_length=25, min_length=3, widget=forms.TextInput( attrs={ 'placeholder': _('Имя'), 'class': "w-full"}), error_messages={'required': _("Это поле обязательно к заполнению")}) email = forms.EmailField( widget=forms.EmailInput( attrs={ 'placeholder': _('Почта'), 'class': "w-full"}), error_messages={'required': _("Это поле обязательно к заполнению")}) message = forms.CharField( widget=forms.Textarea( attrs={ 'placeholder': _('Твоё сообщение'), 'class': "w-full"}), error_messages={'required': _("Это поле обязательно к заполнению")}) captcha = CaptchaField( widget=CaptchaTextInput( attrs={'class': "w-full"}), error_messages={'required': _("Каптча заполнена неверно")})
    Для того чтобы подстроить поле формы под себя, нужно указать для него специальный виджет. В виджетах можно указать значения любых атрибутов(attrs) и так же указать сообщение с ошибкой(error_messages).
    Да, знаю, было бы классно если бы можно было указать сообщение с ошибкой в одном месте, DRY-принцип. Но я увы не нашёл способ это сделать ヽ(`⌒´メ)ノ
    На этом с формой всё. Когда закончим с созданием формы обратной связи, мы всегда сможем добавить или удалить ненужные поля. И нам больше ничего не придётся делать, ибо всё уже будет сделано и предварительно настроено.

    Разработаем и подключим класс-представление FeedbackView

    Осталось обработать входящую форму и вернуть её. Плюс сообщение о статусе формы. Представление формы получается очень простым, хотя не без нюансов. Вот сразу её код:
    from django.core.mail import send_mail from django.views.generic import FormView from .forms import FeedbackForm class FeedbackView(FormView): template_name = 'parts/feedback-form.html' form_class = FeedbackForm def form_valid(self, form): subject = f'{form.cleaned_data.get("username")} | {form.cleaned_data.get("email")}' message = f'{form.cleaned_data.get("message")}' #send_mail(subject=subject, message=message, from_email=DEFAULT_FROM_EMAIL, recipient_list=[DEFAULT_TO_EMAIL]) return self.render_to_response(self.get_context_data(form=FeedbackForm(), success_feedback_message=_("Успех"))) def form_invalid(self, form): return self.render_to_response(self.get_context_data(form=form, error_feedback_message=_("Ошибка")))
    Начнём по порядку. Если делать всё по официальной документации, то кроме указания таких членов класса, как template_name и form_class нужно ещё будет указать success_url.
    success_url - это то URL, на которое будет совершён редирект, после успешной отправки формы.
    И в некоторых случаях это будет уместно, но не в нашем. По крайней мере я не нашёл редирект необходимым для меня. Поэтому немного подсмотрев в исходный код родительского класса(FormMixin), переопределил метод form_valid и просто вернул форму с сообщением о результате на клиент.
    Ну и конечно же, подключим созданный класс-представление, в urls.py:
    from django.urls import path from Backend import views urlpatterns = [ path('api/raw_delete/', views.raw_delete, name="raw_delete"), path('feedback/', views.FeedbackView.as_view()), ]

    Заключение

    Я понимаю, что форма обратной связи предполагает отправку писем на контактный адрес почты. Хотя это не строго обязательно. Можно например собирать эти письма на отдельную таблицу(Django-модель) в базе данных, а там уже делать с ними что-нибудь(сортировать, удалять, делать рассылку и прочее).
    Про то, как можно будет подключить django-сайт к почтовым серверам хостингов я расскажу, как-нибудь отдельно. Ну а пока, имеем один из способов, как можно добавить форму обратной связи на сайт, django-сайт.
    И как просто это однако с HTMx, никакого JS кода, только HTML и Python. Приятно однако.


    Не забудь поделиться, лайкнуть и оставить комментарий)

    Комментарии

    (0)

    captcha
    Отправить
    ЗАГРУЗКА ...
    Сейчас тут пусто. Буть первым (o゚v゚)ノ

    Другое

    Похожие статьи


    Django, HTMx pagination, как сделать простой пагинатор ч. 1

    Часы
    02.04.2025
    /
    Часы
    01.10.2025
    Глазик
    349
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я опишу то, как создать пагинатор используя Django и HTMx библиотеку. И то, почему это было так просто в сравнении с пагинатором на моём сайте. С шаблонами …

    Как сделать простой пагинатор на Django и HTMx. Добавляем сортировку и фильтры ч. 2

    Часы
    08.04.2025
    /
    Часы
    01.10.2025
    Глазик
    387
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я опишу процесс и основные блоки кода, для того чтобы добавить сортировку и фильтрацию к пагинатору. Данный пагинатор написан на Django используя HTMx.

    Как добавить свою 404, 500 страницу в Django

    Часы
    12.04.2025
    /
    Часы
    01.10.2025
    Глазик
    715
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я опишу процесс создания страниц ошибок 404 и 500. Я покажу два основных способа как это сделать и то как можно быстро и легко настроить сервер для …

    Туториал про то, как добавить карту сайта (sitemap) на Django сайт

    Часы
    17.04.2025
    /
    Часы
    01.10.2025
    Глазик
    634
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я опишу самый простой и понятный способ добавления карты сайта(sitemap) к Django сайту. Тут ты найдёшь три различных типа имплементации карт сайта, для статических страниц, для страниц …

    Использованные термины


    Релевантные вопросы