Евгений Легоцкой15 октября 2016 г. 9:50

Django - Урок 013. Контактная форма на Django

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

Тем более, что для сайта на Wordpress это было для меня больной темой. Наверное, всему виной была лень, ибо у меня так и не возникло желания начать разбираться с PHP , чтобы набросать контактную форму самостоятельно (в итоге был задействован очередной плагин).

А если учесть, что разработка на Django , предполагает достаточно частую работу с различными формами данных и при этом имеется модуль для работы с почтовыми сервисами, то и добавление подобной формы не представляет особого труда.

Настройка settings.py, urls.py, home/urls.py

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

EMAIL_HOST = 'smtp.example.com'          # Сервер для отправки сообщений
EMAIL_HOST_USER = 'info@example.com'     # имя пользователя
EMAIL_HOST_PASSWORD = 'password123'      # пароль от ящика
EMAIL_PORT = 2525                        # порт для подключения
EMAIL_USE_TLS = True                     # использование протокола шифрования
DEFAULT_FROM_EMAIL = 'info@example.com'  # email, с которого будет отправлено письмо

Также в данном файле необходимо указать то приложение, которое будет отвечать за контактную форму. В моём случае это приложение home, которое отвечает за редко меняющиеся страницы, например, страницу с контактной формой. А также используемый на сайте модуль django-bootstrap3

INSTALLED_APPS = [
    ...
    'home.apps.HomeConfig',
    'bootstrap3',
    ...
]

Естественно в основном файле urls.py указан шаблон, по которому в данное приложение отправляется запрос.

urlpatterns = [
    url(r'^', include('home.urls')),
]

Что касается шаблона url для приложения home , то он будет выглядеть следующим образом:

from django.conf.urls import url

from . import views

app_name = 'home'
urlpatterns = [
    ...
    url(r'^contacts/$', views.EContactsView.as_view(), name='contacts'),
    ...
]

Контактная форма

В контактной форме присутствует три поля:

  1. Имя - пользователь обязательно должен представиться;
  2. email - пользователь должен указать свою электронную почту, чтобы была возможность ему ответить;
  3. Сообщение - непосредственно само сообщение, которое пользователь желает отправить.

Все поля будут обязательными. При этом проверка корректности ввода email будет осуществляться ещё в браузере пользователя.

# -*- coding: utf-8 -*-

from django import forms


class ContactForm(forms.Form):

    name = forms.CharField(
        label="Имя",
        widget=forms.TextInput
    )

    email = forms.EmailField(
        widget=forms.EmailInput
    )

    message = forms.CharField(
        label="Сообщение",
        widget=forms.Textarea
    )

Представление

А теперь напишем представление, которое будет отвечать за обработку сообщения и отображение страницы с контактной формой.

from django.shortcuts import render_to_response, reverse
from django.views import View
from django.core.mail import send_mail

from .forms import ContactForm
from project import settings


class EContactsView(View):
    template_name = 'home/contacts.html'

    # В случае get запроса, мы будем отправлять просто страницу с контактной формой
    def get(self, request, *args, **kwargs):
        context = {}
        context.update(csrf(request))    # Обязательно добавьте в шаблон защитный токен
        context['contact_form'] = ContactForm()

        return render_to_response(template_name=self.template_name, context=context)

    def post(self, request, *args, **kwargs):
        context = {}

        form = ContactForm(request.POST)

        # Если не выполнить проверку на правильность ввода данных,
        # то не сможем забрать эти данные из формы... хотя что здесь проверять?
        if form.is_valid():
            email_subject = 'EVILEG :: Сообщение через контактную форму '
            email_body = "С сайта отправлено новое сообщение\n\n" \
                         "Имя отправителя: %s \n" \
                         "E-mail отправителя: %s \n\n" \
                         "Сообщение: \n" \
                         "%s " % \
                         (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'])

            # и отправляем сообщение
            send_mail(email_subject, email_body, settings.EMAIL_HOST_USER, ['target_email@example.com'], fail_silently=False)

        return render_to_response(template_name=self.template_name, context=context)

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

Шаблон контактной формы

В контактной форме обязательно необходимо указать {% csrf_token %}, который будет защищать ваш сайт от атак через контактную форму. А также не забудьте подгрузить модуль bootsrtap3 , который позволит создать более корректный и красивый вид страницы.

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

{% extends 'home/base.html' %}{% load bootstrap3 %}
{% block title %}Контакты{% endblock %}
{% block page %}
    <h1>Контакты</h1>
    <article>
    {% if contact_form %}
        <p>Добро пожаловать на сайт.</p>
        <p>Если у Вас есть пожелания или предложения по улучшению сайта, либо Вы желаете предложить статью к публикации на сайте, то Вы можете сделать это, воспользовавшись контактной формой:</p>
        <form id="contact_form" action="{% url 'home:contacts' %}" method="post">
            {% csrf_token %}
            {% bootstrap_form contact_form %}
            {% buttons %}
                <button type="submit" class="btn btn-primary">{% bootstrap_icon "send" %}&nbsp;&nbsp;Отправить</button>
            {% endbuttons %}
        </form>
    {% else %}
        <p>Сообщение отправлено</p>
    {% endif %}
    </article>
{% endblock %}

Для Django рекомендую VDS-сервера хостера Timeweb .

Код контактной формы будет располагаться в файле forms.py.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Поддержать автора Donate
DR

Не полноценное решение, сильно вырвано из контекста.

B

Здавствуйте! обязательно ли форма в django должна быть привязана к модели? конкретно в этом случаи

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

S

Добрый день,
не могу отправить загруженный файл, подскажите что нужно еще добавить.
Спасибо.

forms:
class ContactForm(forms.Form):

    name = forms.CharField(
        label="Имя",
        widget=forms.TextInput
    )

    email = forms.EmailField(
        widget=forms.EmailInput
    )

    message = forms.CharField(
        label="Сообщение", required=False,
        widget=forms.Textarea
    )
    file = forms.FileField(
        label="Загрузить файл", required=False,
    )

views:
class EContactsView(View):
    template_name = 'main/contacts.html'

    # В случае get запроса, мы будем отправлять просто страницу с контактной формой
    def get(self, request, *args, **kwargs):
        context = {}
        context['contact_form'] = ContactForm()
        return render(request, template_name=self.template_name, context=context)

    def post(self, request, *args, **kwargs):
        context = {}

        form = ContactForm(request.POST, request.FILES)

        # Если не выполнить проверку на правильность ввода данных,
        # то не сможем забрать эти данные из формы... хотя что здесь проверять?
        if form.is_valid():

            email_subject = ':: Сообщение через контактную форму '
            email_body = "С сайта отправлено новое сообщение\n\n" \
                         "Имя отправителя: %s \n" \
                         "E-mail отправителя: %s \n\n" \
                         "Сообщение: \n" \
                         "%s " % \
                         (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'], form.cleaned_data['file'])


            # и отправляем сообщение

            send_mail(email_subject, email_body, settings.EMAIL_HOST_USER, ['mymail@gmail.com'], fail_silently=False)

        return render(request, template_name=self.template_name, context=context)

шаблон:

{% extends "layout/basic.html" %}
{% load thumbnail %}
{% load static %}
{% load bootstrap4 %}
{% block title %}Контакты{% endblock %}

{% block content %}
    <h1>Контакты</h1>
    <article>
    {% if contact_form %}
        <p>Добро пожаловать на сайт.</p>
        <p>Если у Вас есть пожелания или предложения по улучшению сайта, либо Вы желаете предложить статью к публикации на сайте, то Вы можете сделать это, воспользовавшись контактной формой:</p>
        <form id="contact_form" action="{% url 'main:contacts' %}" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            {% bootstrap_form contact_form %}

            {% buttons %}
                <button type="submit" class="btn btn-success">&nbsp;&nbsp;Отправить</button>
            {% endbuttons %}
        </form>
    {% else %}
        <p>Сообщение отправлено</p>
    {% endif %}
    </article>
{% endblock %}

Добрый день.
Потому, что нужно не добавлять ссылку (или что там у вас в итоге получается) на файл и прикреплять его к письму.
Если не ошибаюсь, то для отправки письма с файлом нужно использовать класс EmailMessage

def send_email(request):
    ...
    email = EmailMessage(
        subject,
        content,
        contact_email,
        [to],
        headers={'Reply-To': contact_email}
    )
    if request.FILES:
        uploaded_file = request.FILES['file'] # file is the name value which you have provided in form for file field
        email.attach(uploaded_file.name, uploaded_file.read(), uploaded_file.content_type)
    email.send()

Могут быть некоторые разночтения в синтаксисе, в зависимости от версий Django

S

Добрый день, в итоге получилось как-то так, отправляет форму с файлом.
Спасибо.

settings:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

views:

from django.core.mail import EmailMessage
from django.conf import settings

def contacts(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            email_subject = ' Сообщение через контактную форму '
            email_body = "С сайта отправлено новое сообщение\n\n" \
                         "Имя отправителя: %s \n" \
                         "E-mail отправителя: %s \n\n" \
                         "Сообщение: \n" \
                         "%s " % \
                         (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'])

    email = EmailMessage(
        email_subject,
        email_body,
        settings.EMAIL_HOST_USER,
        ['mymail@gmail.com'],
    )
    if request.FILES:
        uploaded_file = request.FILES['file'] # file is the name value which you have provided in form for file field
        email.attach(uploaded_file.name, uploaded_file.read(), uploaded_file.content_type)
    email.fail_silently=False

    email.send()
    return render(request, 'main/contacts.html')
S

Добрый день,
при отправки письма с файлом, выбираю несколько файлов, пишет выбранное количество файлов, а отправляет только один, весь код см.выше, добавил только в форму возможность выбора нескольких файлов. Подскажите,что нужно еще добавить, чтобы можно было отправить сразу несколько файлов.
Спасибо.

class ContactForm(forms.Form):
file = forms.FileField(
        label="Загрузить файл", required=False,
        widget = forms.FileInput(attrs={'multiple': True})

    )

Думаю, что как-то так, возможно неправильно написание имени метода getlist, но выглядеть должно так

if request.FILES:
    for f in request.FILES.getlist('file'):
        email.attach(f.name, f.read(), f.content_type)
S

Спасибо, Евгений.
Все заработало.

def contacts(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            email_subject = ' Сообщение через контактную форму '
            email_body = "С сайта отправлено новое сообщение\n\n" \
                         "Имя отправителя: %s \n" \
                         "E-mail отправителя: %s \n\n" \
                         "Сообщение: \n" \
                         "%s " % \
                         (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'])

        email = EmailMessage(
            email_subject,
            email_body,
            settings.EMAIL_HOST_USER,
            ['mymail@gmail.com'],
            )
        if request.FILES:
            for f in request.FILES.getlist('file'):
                email.attach(f.name, f.read(), f.content_type)
        email.fail_silently=False
        email.send()
    return render(request, 'main/contacts.html')

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
Card image cap
Pulsum Via

Проект для путешественников от EVILEG.

Перейти
Timeweb

Позвольте мне порекомендовать вам отличный хостинг, на котором расположен EVILEG.

В течение многих лет Timeweb доказывает свою стабильность.

Для проектов на Django рекомендую VDS хостинг

Посмотреть Хостинг
Поделиться в социальных сетях
Donate

Проект EVILEG перешёл на некоммерческую основу и будет развиваться исключительно на энтузиазме создателя сайта, энтузиазме пользователей, пожертвованиях и реферальной системе хостинга

Спасибо за вашу поддержку

Доступные способы поддержки проекта

PayPal

PatreonYooMoneyПодробнее

C++ - Тест 001. Первая программа и типы данных

  • Результат:80баллов,
  • Очки рейтинга4

C++ - Тест 001. Первая программа и типы данных

  • Результат:66баллов,
  • Очки рейтинга-1
ГР

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:90баллов,
  • Очки рейтинга8
Последние комментарии

Qt/C++ - Урок 061. Добавление изображений в приложение методом Drag And Drop из файлового менеджера

Доброго времени суток. А если нужно и изображение и текст? Что-то потерялся немного.... // Вместо отрисовки иконки и текста будем отрисовывать только одно изображение // с н…
АС

Qt/C++ - Урок 004. QSqlTableModel или Как представить таблицу из БД в Qt?

error insert into TableExample " Количество параметров не совпадает" Я путь свой прописывала и даже бд удаляла, чтобы заново сделать, не работает. (всё остальное как у вас... Вроде ка…
i
ЛД

GameDev на Qt - Урок 1. Отслеживание перемещения мыши в QGraphicsScene

Вполне возможно, что ты не закинул graphicsView в дизайнере в виджет
ЛД

GameDev на Qt - Урок 1. Отслеживание перемещения мыши в QGraphicsScene

Кому интересно, поворот в slotTarget можно в одну строку организовать this->setRotation(90 + rotation() + qRadiansToDegrees(qAtan2(mapFromScene(point).y(), mapFromScene(point).x())));
Сейчас обсуждают на форуме
M

Sorting the added QML elements in the ListModel

legal online pharmacy
  • Nomad
  • 30 июля 2022 г. 5:42

Как работать с HTMX?

Приветствую колеги. На днях наткнулся на вот это : https://htmx.org/ На офф сайте написанно вот такая фраза: htmx gives you access to AJAX, CSS Transitions, We…
h
  • harisr
  • 25 июля 2022 г. 2:56

QT - Native App Integration

Привет, у нас уже есть собственное приложение для Android. Можем ли мы интегрировать пользовательское представление QT в приложение со всем приложением QT внутри представления. Если да, ука…

Правильный запуск сервера на vps - Django

О я как то себе дома локальный сервер создавал. Вам же нужно просто сделать ручками конфигурацию системы. Настроить Nginx ну либо Apache (тут кому что нравится). Соответственно БД и всё остально…
o

Распознание объектов

Я к тому, что, возможно, софт уже есть.
О нас
Услуги
© EVILEG 2015-2022
Рекомендует хостинг TIMEWEB