Evgenii Legotckoi
Oct. 15, 2016, 7:50 p.m.

Django - Tutorial 013. Contact form based on Django

Continuing the development of the site, I would like to share an example of code for adding a contact form on the site to Django. There have already been articles with different shapes, for example, to add comments, but just talking about the entire process as a whole, and we will not get, and this theme party.

Especially that for a site on Wordpress for me it was a pain. Probably, all the fault was laziness, because I did not have any desire to begin to deal with PHP , to sketch out a contact form on their own (as a result of another plugin was used).

And when you consider that the development on the Django , quite often involves working with various forms of data, and thus there is a module for working with e-mail services, and the addition of such a form is not difficult.


Configuring settings.py, urls.py, home/urls.py

The first thing to do is to set up the configuration file, because it will be necessary to specify the data for connecting to the mailbox from which you will be sent a letter with the contents of the contact form.

  1. EMAIL_HOST = 'smtp.example.com' # Server for sending messages
  2. EMAIL_HOST_USER = 'info@example.com' # Username
  3. EMAIL_HOST_PASSWORD = 'password123' # Password
  4. EMAIL_PORT = 2525 # port of protocol
  5. EMAIL_USE_TLS = True # using encoding
  6. DEFAULT_FROM_EMAIL = 'info@example.com' # email

Also, in this file you must specify the application that will be responsible for the contact form. In my case, this is the app home, which is responsible for rarely changing pages, such as a contact form. Also used on the site django-bootstrap3 module.

  1. INSTALLED_APPS = [
  2. ...
  3. 'home.apps.HomeConfig',
  4. 'bootstrap3',
  5. ...
  6. ]

Of course mostly urls.py file Set the template on which the request is sent to the application.

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

With regard to the url template for home application, it will be as follows:

  1. from django.conf.urls import url
  2.  
  3. from . import views
  4.  
  5. app_name = 'home'
  6. urlpatterns = [
  7. ...
  8. url(r'^contacts/$', views.EContactsView.as_view(), name='contacts'),
  9. ...
  10. ]

Contact form

The contact form is present three fields:

  1. Username - the user which must be presented;
  2. email - the user which must specify your e-mail, to be able to answer him;
  3. Message

All fields are mandatory. The check entry correctness email will be back in the user's browser.

Contact form code will be located in forms.py file.

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django import forms
  4.  
  5.  
  6. class ContactForm(forms.Form):
  7.  
  8. name = forms.CharField(
  9. label="Имя",
  10. widget=forms.TextInput
  11. )
  12.  
  13. email = forms.EmailField(
  14. widget=forms.EmailInput
  15. )
  16.  
  17. message = forms.CharField(
  18. label="Сообщение",
  19. widget=forms.Textarea
  20. )

View

Now write view, which will be responsible for processing the message and display a page with a contact form.

  1. from django.shortcuts import render_to_response, reverse
  2. from django.views import View
  3. from django.core.mail import send_mail
  4.  
  5. from .forms import ContactForm
  6. from project import settings
  7.  
  8.  
  9. class EContactsView(View):
  10. template_name = 'home/contacts.html'
  11.  
  12. # В случае get запроса, мы будем отправлять просто страницу с контактной формой
  13. def get(self, request, *args, **kwargs):
  14. context = {}
  15. context.update(csrf(request)) # Обязательно добавьте в шаблон защитный токен
  16. context['contact_form'] = ContactForm()
  17.  
  18. return render_to_response(template_name=self.template_name, context=context)
  19.  
  20. def post(self, request, *args, **kwargs):
  21. context = {}
  22.  
  23. form = ContactForm(request.POST)
  24.  
  25. # Если не выполнить проверку на правильность ввода данных,
  26. # то не сможем забрать эти данные из формы... хотя что здесь проверять?
  27. if form.is_valid():
  28. email_subject = 'EVILEG :: Сообщение через контактную форму '
  29. email_body = "С сайта отправлено новое сообщение\n\n" \
  30. "Имя отправителя: %s \n" \
  31. "E-mail отправителя: %s \n\n" \
  32. "Сообщение: \n" \
  33. "%s " % \
  34. (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'])
  35.  
  36. # и отправляем сообщение
  37. send_mail(email_subject, email_body, settings.EMAIL_HOST_USER, ['target_email@example.com'], fail_silently=False)
  38.  
  39. return render_to_response(template_name=self.template_name, context=context)

Here there is one key point concerning the display of the page to the user. If the user is sent a letter, it must inform you that the message was sent. To do this, we simply will not be placed in the context of a contact form in the template to check for its presence, to display the correct information to the user.

Template of contact form

The contact form is necessarily necessary to specify {% csrf_token%} , which will protect your site from attack via the contact form. And also do not forget to load bootsrtap3 module that will create a more correct and beautiful look of the page.

To use the contact form module bootstrap3 only need to specify the appropriate template tag and send our contact form to it. I draw your attention to the fact that depending on the availability of the contact form different appearance of the page will be displayed.

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

For Django I recommend VDS-server of Timeweb hoster Timeweb hoster .

DR
  • May 31, 2019, 9:12 p.m.
  • (edited)

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

B
  • Dec. 26, 2019, 12:08 p.m.

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

Evgenii Legotckoi
  • Jan. 6, 2020, 2:16 p.m.

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

S
  • May 17, 2020, 4:37 p.m.

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

  1. forms:
  2. class ContactForm(forms.Form):
  3.  
  4. name = forms.CharField(
  5. label="Имя",
  6. widget=forms.TextInput
  7. )
  8.  
  9. email = forms.EmailField(
  10. widget=forms.EmailInput
  11. )
  12.  
  13. message = forms.CharField(
  14. label="Сообщение", required=False,
  15. widget=forms.Textarea
  16. )
  17. file = forms.FileField(
  18. label="Загрузить файл", required=False,
  19. )
  20.  
  21. views:
  22. class EContactsView(View):
  23. template_name = 'main/contacts.html'
  24.  
  25. # В случае get запроса, мы будем отправлять просто страницу с контактной формой
  26. def get(self, request, *args, **kwargs):
  27. context = {}
  28. context['contact_form'] = ContactForm()
  29. return render(request, template_name=self.template_name, context=context)
  30.  
  31. def post(self, request, *args, **kwargs):
  32. context = {}
  33.  
  34. form = ContactForm(request.POST, request.FILES)
  35.  
  36. # Если не выполнить проверку на правильность ввода данных,
  37. # то не сможем забрать эти данные из формы... хотя что здесь проверять?
  38. if form.is_valid():
  39.  
  40. email_subject = ':: Сообщение через контактную форму '
  41. email_body = "С сайта отправлено новое сообщение\n\n" \
  42. "Имя отправителя: %s \n" \
  43. "E-mail отправителя: %s \n\n" \
  44. "Сообщение: \n" \
  45. "%s " % \
  46. (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'], form.cleaned_data['file'])
  47.  
  48.  
  49. # и отправляем сообщение
  50.  
  51. send_mail(email_subject, email_body, settings.EMAIL_HOST_USER, ['mymail@gmail.com'], fail_silently=False)
  52.  
  53. return render(request, template_name=self.template_name, context=context)
  54.  
  1. шаблон:
  2.  
  3. {% extends "layout/basic.html" %}
  4. {% load thumbnail %}
  5. {% load static %}
  6. {% load bootstrap4 %}
  7. {% block title %}Контакты{% endblock %}
  8.  
  9. {% block content %}
  10. <h1>Контакты</h1>
  11. <article>
  12. {% if contact_form %}
  13. <p>Добро пожаловать на сайт.</p>
  14. <p>Если у Вас есть пожелания или предложения по улучшению сайта, либо Вы желаете предложить статью к публикации на сайте, то Вы можете сделать это, воспользовавшись контактной формой:</p>
  15. <form id="contact_form" action="{% url 'main:contacts' %}" method="post" enctype="multipart/form-data">
  16. {% csrf_token %}
  17. {% bootstrap_form contact_form %}
  18.  
  19. {% buttons %}
  20. <button type="submit" class="btn btn-success">&nbsp;&nbsp;Отправить</button>
  21. {% endbuttons %}
  22. </form>
  23. {% else %}
  24. <p>Сообщение отправлено</p>
  25. {% endif %}
  26. </article>
  27. {% endblock %}
Evgenii Legotckoi
  • May 18, 2020, 1:20 p.m.

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

  1. def send_email(request):
  2. ...
  3. email = EmailMessage(
  4. subject,
  5. content,
  6. contact_email,
  7. [to],
  8. headers={'Reply-To': contact_email}
  9. )
  10. if request.FILES:
  11. uploaded_file = request.FILES['file'] # file is the name value which you have provided in form for file field
  12. email.attach(uploaded_file.name, uploaded_file.read(), uploaded_file.content_type)
  13. email.send()

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

S
  • May 20, 2020, 5:08 p.m.

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

  1. settings:
  2.  
  3. EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
  4.  
  5. views:
  6.  
  7. from django.core.mail import EmailMessage
  8. from django.conf import settings
  9.  
  10. def contacts(request):
  11. if request.method == 'POST':
  12. form = ContactForm(request.POST)
  13. if form.is_valid():
  14. email_subject = ' Сообщение через контактную форму '
  15. email_body = "С сайта отправлено новое сообщение\n\n" \
  16. "Имя отправителя: %s \n" \
  17. "E-mail отправителя: %s \n\n" \
  18. "Сообщение: \n" \
  19. "%s " % \
  20. (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'])
  21.  
  22. email = EmailMessage(
  23. email_subject,
  24. email_body,
  25. settings.EMAIL_HOST_USER,
  26. ['mymail@gmail.com'],
  27. )
  28. if request.FILES:
  29. uploaded_file = request.FILES['file'] # file is the name value which you have provided in form for file field
  30. email.attach(uploaded_file.name, uploaded_file.read(), uploaded_file.content_type)
  31. email.fail_silently=False
  32.  
  33. email.send()
  34. return render(request, 'main/contacts.html')
S
  • May 22, 2020, 5:52 p.m.

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

  1. class ContactForm(forms.Form):
  2. file = forms.FileField(
  3. label="Загрузить файл", required=False,
  4. widget = forms.FileInput(attrs={'multiple': True})
  5.  
  6. )
Evgenii Legotckoi
  • May 22, 2020, 5:57 p.m.

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

  1. if request.FILES:
  2. for f in request.FILES.getlist('file'):
  3. email.attach(f.name, f.read(), f.content_type)
S
  • May 22, 2020, 9:10 p.m.

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

  1. def contacts(request):
  2. if request.method == 'POST':
  3. form = ContactForm(request.POST)
  4. if form.is_valid():
  5. email_subject = ' Сообщение через контактную форму '
  6. email_body = "С сайта отправлено новое сообщение\n\n" \
  7. "Имя отправителя: %s \n" \
  8. "E-mail отправителя: %s \n\n" \
  9. "Сообщение: \n" \
  10. "%s " % \
  11. (form.cleaned_data['name'], form.cleaned_data['email'], form.cleaned_data['message'])
  12.  
  13. email = EmailMessage(
  14. email_subject,
  15. email_body,
  16. settings.EMAIL_HOST_USER,
  17. ['mymail@gmail.com'],
  18. )
  19. if request.FILES:
  20. for f in request.FILES.getlist('file'):
  21. email.attach(f.name, f.read(), f.content_type)
  22. email.fail_silently=False
  23. email.send()
  24. return render(request, 'main/contacts.html')
d
  • Feb. 16, 2023, 10:15 p.m.

Timeweb так себе провайдер.
Поддержка не отвечает. И smtp не отправляет письма.
Все перепробовал ничего найти не могу.
1. Ошибка sock.connect(sa) TimeoutError: [Errno 110] Connection timed out
2. Ошибка OSError: [Errno 101] Network is unreachable

Comments

Only authorized users can post comments.
Please, Log in or Sign up
  • Last comments
  • Evgenii Legotckoi
    March 9, 2025, 9:02 p.m.
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    March 9, 2025, 4:14 p.m.
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
  • ИМ
    Nov. 22, 2024, 9:51 p.m.
    Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
  • Evgenii Legotckoi
    Oct. 31, 2024, 11:37 p.m.
    Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
  • A
    Oct. 19, 2024, 5:19 p.m.
    Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html