Отправка электронных писем в представлениях
Отредактируйте представление post_share в файле views.py приложения blog, как показано ниже:
from django.core.mail import send_mail
from django.conf import settings
def post_share(request, post_id):
# Извлечь пост по его идентификатору id
post = get_object_or_404(Post,
id=post_id,
status=Post.Status.PUBLISHED)
sent = False
if request.method == 'POST':
# Форма была передана на обработку
form = EmailPostForm(request.POST)
if form.is_valid():
# Поля формы успешно прошли валидацию
cd = form.cleaned_data
post_url = request.build_absolute_uri(
post.get_absolute_url())
subject = f"{cd['name']} recommends you read " \
f"{post.title}"
message = f"Read {post.title} at {post_url}\n\n" \
f"{cd['name']}\'s ({cd['email']}) comments: {cd['comments']}"
send_mail(subject, message, settings.EMAIL_HOST_USER,
[cd['to']])
sent = True
else:
form = EmailPostForm()
return render(request, 'blog/post/share.html', {'post': post,
'form': form,
'sent': sent})
Если вы используете SMTP-сервер, а не почтовый бэкенд console.EmailBackend, то замените your_account@gmail.com своей реальной учетной записью электронной почты.
В приведенном выше исходном коде мы объявили переменную sent с изначальным значением False. Мы задаем этой переменной значение True после отправки электронного письма. Позже мы будем использовать переменную sent в шаблоне отображения сообщения об успехе при успешной передаче формы.
Поскольку ссылка на пост должна вставляться в электронное письмо, мы получаем абсолютный путь к посту, используя его метод get_absolute_url().
Мы используем этот путь на входе в метод request.build_absolute_uri(), чтобы сформировать полный URL-адрес, включая HTTP-схему и хост-имя (hostname).
Мы создаем тему и текст сообщения электронного письма, используя очищенные данные валидированной формы.
Наконец, мы отправляем электронное письмо на адрес электронной почты, указанный в поле to(Кому) формы.
Теперь, когда представление post_share завершено, для него необходимо добавить новый шаблон URL-адреса.
Откройте файл urls.py приложения blog и добавьте шаблон URL-адреса post_share, как показано ниже:
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
# представления поста
# path('', views.post_list, name='post_list'),
path('', views.PostListView.as_view(), name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
path('<int:post_id>/share/',
views.post_share, name='post_share'),
]
Прорисовка форм в шаблонах
После того как была создана форма, запрограммировано представление и добавлен шаблон URL-адреса, не хватает только одного – шаблона представления.
Внутри каталога /templates/blog/post/ создайте новый файл и назовите его share.html.
Добавьте следующий ниже исходный код в новый шаблон share.html:
{% extends "blog/base.html" %}
{% block title %}Share a post{% endblock %}
{% block content %}
{% if sent %}
<h1>E-mail successfully sent</h1>
<p>
"{{ post.title }}" was successfully sent
to {{ form.cleaned_data.to }}.
</p>
{% else %}
<h1>Share "{{ post.title }}" by e-mail</h1>
<form method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Send e-mail">
</form>
{% endif %}
{% endblock %}
Это шаблон, который используется для отображения формы, служащей для того, чтобы делиться постом по электронной почте, и для отображения успешного сообщения после отправки электронного письма. Различие между обоими случаями проводится с помощью тега {% if sent %}.
Для того чтобы отобразить форму, мы определили HTML-элемент form, указав, что форма должна быть передана методом POST:
<form method="post">
Экземпляр формы вставлен с помощью тега {{ form.as_p }}. При этом веб-фреймворку Django сообщается, что нужно прорисовывать поля формы, используя абзацные HTML-элементы <p> с применением метода as_p.
Кроме того, форму можно было бы прорисовывать в виде неупорядоченного списка с использованием метода as_ul или в виде HTML-таблицы с применением метода as_table, а также в виде div контейнеров с помощью тега {{ form.as_div }}
Еще одним вариантом является прорисовка каждого поля путем прокручивания полей формы в цикле, как в следующем ниже примере:
{% for field in form %}
<div>
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
Здесь добавлен шаблонный тег {% csrf_token %}. Указанный тег вводит скрытое поле с автоматически сгенерированным токеном во избежание атак по подделке межсайтовых запросов (CSRF). Такие атаки заключаются в том, что вредоносный веб-сайт или программа выполняют нежелательные для пользователя действия на сайте.
Более подробная информация о подделке межсайтовых запросов находится на странице https://owasp.org/www-community/attacks/csrf.
По умолчанию Django проверяет наличие токена CSRF во всех запросах методом POST. Тег csrf_token следует вставлять во все формы, передаваемые на обработку методом POST.
Шаблонный тег {% csrf_token %} генерирует скрытое поле, которое прорисовывается следующим образом:
<input type='hidden' name='csrfmiddlewaretoken'
value='26JjKo2lcEtYkGoV9z4XmJIEHLXN5LDR' />
Отредактируйте шаблон blog/post/detail.html, придав ему следующий вид:
{% extends "blog/base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|linebreaks }}
<p>
<a href="{% url 'blog:post_share' post.id %}">
Share this post
</a>
</p>
{% endblock %}
Здесь была добавлена ссылка на URL-адрес post_share. URL-адрес формируется динамически с помощью предоставляемого веб-фреймворком Django шаблонного тега {% url %}. При этом используются именное пространство blog и URL-адрес post_share.
Для того чтобы сформировать URL-адрес, id поста передается в качестве параметра. Откройте приглашение командной оболочки и исполните следующую ниже команду, чтобы запустить сервер разработки и пройдите по URL-адресу http://127.0.0.1:8000/blog/ в своем браузере и кликните по заголовку любого поста, чтобы просмотреть страницу детальной информации о посте.
Под телом поста вы должны увидеть ссылку, которую вы только что добавили:
Кликните по Share this post(Поделиться этим постом), и вы должны увидеть страницу, включая форму, позволяющую делиться этим постом по электронной почте, как показано ниже:
Стили CSS формы включены в пример исходного кода и находятся в файле static/css/blog.css. При нажатии кнопки SEND E-MAIL(Отправить электронное письмо) форма передается на обработку и затем валидируется.
Если все поля содержат валидные данные, то вы получите сообщение об успехе, как показано ниже:
Отправьте пост на свой собственный адрес электронной почты и проверьте свой почтовый ящик. Полученное вами электронное письмо должно выглядеть следующим образом:
Если передать форму на обработку с не валидными данными, то форма будет прорисована снова, выводя все ошибки валидации.
Большинство современных браузеров не позволят передавать форму на обработку с пустыми или ошибочными полями. Это вызвано тем, что перед передачей формы на обработку браузер проверяет поля на основе их атрибутов. В этом случае форма не будет передана на обработку, и браузер отобразит сообщение об ошибке у неправильных полей.
Для того чтобы протестировать валидацию формы Django с использованием современного браузера, можно пропустить валидацию формы браузером, добавив атрибут novalidate в элемент HTML <form>.
Например, <form method="post" novalidate>. Этот атрибут можно добавлять, чтобы запрещать браузеру валидировать поля и тестировать свою собственную валидацию формы. После завершения тестирования удалите атрибут novalidate, чтобы вернуть валидацию формы браузером.
Теперь функциональность, позволяющая делиться постами по электронной почте, завершена.
Более подробная информация о работе с формами находится на странице https://docs.djangoproject.com/en/5.0/topics/forms/.