Статьи

Введение в Flask: добавление контактной страницы

В предыдущей статье этой мини-серии мы использовали Flask для создания простого веб-сайта, содержащего страницы «Главная» и «О программе», используя обобщенный рабочий процесс, который мы можем применить к другим веб-приложениям на основе Flask. В этом уроке я покажу, как добавить страницу «Контакты», которая позволяет пользователям отправлять вам сообщения.

Код, используемый в этой статье, можно найти на GitHub . Подписи, такие как Checkpoint: 05_contact_form , означают, что вы можете переключиться на ветку с именем «05_contact_form» и просмотреть код в тот момент в статье.


Вы можете найти полный список расширений в реестре расширений Flask .

Flask не имеет много функций с полки, что позволяет легко брать и изучать. Не существует объектно-реляционного сопоставителя для взаимодействия с базой данных или интерфейсов администратора для добавления и обновления содержимого. Он предлагает только небольшой набор функций, две из которых мы уже использовали — url_for() и render_template() .

Вместо поставки с дополнительными функциями, модель расширения Flask позволяет добавлять функциональные возможности по мере необходимости. Расширение Flask — это пакет, который добавляет определенные функции в ваше приложение. Например, Flask-SQLAlchemy добавляет поддержку базы данных в ваше приложение, тогда как Flask-Login добавляет поддержку входа / выхода из системы. Вы можете найти полный список расширений в реестре расширений Flask .

Чтобы создать страницу контактов, мы будем использовать Flask-WTF для обработки и проверки данных формы и Flask-Mail для отправки вам данных формы по электронной почте.


Flask-WTF — это расширение, которое обрабатывает и проверяет данные формы. Что это обозначает? Посмотрите на следующий рисунок:

рисунок 1

  1. Пользователь отправляет запрос GET для веб-страницы, содержащей форму.
  2. Пользователь заполняет форму.
  3. Пользователь нажимает кнопку «Отправить», отправляя ее на сервер через POST-запрос.
  4. Сервер проверяет информацию.
  5. Если одно или несколько полей не проверены, веб-страница, содержащая форму, снова загружается с полезным сообщением об ошибке, предлагающим пользователю повторить попытку.
  6. Если все поля проверены, информация о форме используется на следующем шаге в конвейере.

Страница контактов будет содержать поля для имени пользователя, адреса электронной почты, темы и сообщения. Во Flask мы routes.py форму в функцию в routes.py Эта функция называется обработчиком формы. Мы выполним несколько проверок правильности, и если какой-либо из входных данных не пройдет проверку, мы обновим страницу, чтобы отобразить сообщение с описанием ошибки. После того, как все проверки пройдены, мы будем использовать данные формы для следующего шага: по электронной почте сообщение вам, владельцу сайта.

Расширения Flask — это простые, мощные инструменты, расширяющие функциональность вашего приложения на основе Flask.

Вот как работает обработка и проверка форм. Теперь, где мы на самом деле определяем форму? Мы могли бы написать HTML, используя элемент <form> и установить его атрибут action для скрипта Python. Сценарий Python будет отражать форму для захвата каждого поля формы и проверки данных поля формы. Однако, если мы используем эту стратегию, мы бы по существу определили форму дважды — один раз для внешнего интерфейса и один раз для внутреннего.

Было бы здорово определить форму только один раз: в скрипте Python. Это именно то, что позволяет нам Flask-WTF. Мы определим форму только один раз в скрипте Python, а затем позволим Flask-WTF сгенерировать HTML формы для нас. Смысл всего этого в том, чтобы отделить презентацию от контента.

Хватит болтовни. Давайте код.

В качестве первого шага вернемся к изолированной среде разработки, которую мы создали в прошлый раз.

1
2
$ cd flaskapp
$ .

Теперь, когда мы вошли и активировали нашу среду разработки, мы можем безопасно установить Flask-WTF:

1
$ pip install flask-wtf

Давайте теперь определим форму в скрипте Python. У нас уже есть routes.py , который отображает URL-адреса на функции. Давайте не будем загромождать это несвязанным кодом. Вместо этого создайте новый файл с именем forms.py и поместите его в папку app/ .

Приложение / forms.py

1
2
3
4
5
6
7
8
from flask.ext.wtf import Form, TextField, TextAreaField, SubmitField
 
class ContactForm(Form):
  name = TextField(«Name»)
  email = TextField(«Email»)
  subject = TextField(«Subject»)
  message = TextAreaField(«Message»)
  submit = SubmitField(«Send»)

Мы только что создали форму. Что мы сделали? Сначала мы импортировали несколько полезных классов из Flask-WTF — базовый класс Form , текстовое поле, поле textarea для многострочного ввода текста и кнопку отправки. Затем мы создали новый класс с именем ContactForm , унаследованный от базового класса Form . Затем мы создали каждое поле, которое мы хотим видеть в контактной форме. Вместо того, чтобы писать <input type="text">Name</input> в файле HTML, вы пишете name = TextField("Name") .

Теперь давайте использовать нашу форму. Мы хотим, чтобы он появился, когда пользователь заходит на страницу контактов. В терминах Flask мы хотим, чтобы форма отображалась в веб-шаблоне и отображала URL-адрес этого веб-шаблона, чтобы мы могли посетить его в браузере. Это означает, что нам нужно создать новый веб-шаблон и новое сопоставление URL. Давайте начнем с создания нового сопоставления URL.

Это насыщенный действиями раздел, и он может быть немного запутанным. Но держись за меня, и мы справимся.

В качестве первого шага откройте routes.py и импортируйте нашу вновь созданную форму, добавив from forms import ContactForm в начале скрипта.

Приложение / routes.py

1
2
from flask import Flask, render_template
from forms import ContactForm

Вы можете предотвратить атаку CSRF, убедившись, что отправка формы происходит из вашего веб-приложения.

Затем настройте Flask-WTF для обработки эксплойта безопасности, известного как подделка межсайтовых запросов (CSRF). В идеальном мире ваш сервер будет обрабатывать только те формы, которые принадлежат вашему веб-приложению. Другими словами, ваш сервер будет обрабатывать и проверять только те формы, которые вы создали. Однако злоумышленник может создать форму на своем веб-сайте, заполнить ее вредоносной информацией и отправить на свой сервер. Если ваш сервер принимает эту вредоносную информацию, то могут произойти все виды плохих вещей.

Вы можете предотвратить атаку CSRF, убедившись, что отправка формы происходит из вашего веб-приложения. Один из способов сделать это — сохранить уникальный токен, скрытый внутри <form> HTML <form> который не может быть угадан злоумышленниками. Когда форма отправляет сообщение на ваш сервер, сначала проверяется токен. Если токен не совпадает, ваш сервер отклоняет отправку формы и не касается данных формы. Если токен совпадает, сервер переходит к обработке и проверке формы.

Flask-WTF делает все это простым однострочником. Просто настройте Flask-WTF с секретным ключом, и Flask-WTF позаботится о создании уникальных токенов для ваших форм и управлении ими.

Приложение / routes.py

1
2
3
4
5
6
from flask import Flask, render_template, request, flash
from forms import ContactForm
 
app = Flask(__name__)
 
app.secret_key = ‘development key’

Здесь, в шестой строке, я установил секретный ключ как «ключ разработки». Не стесняйтесь делать ваш более сложным, длинным и буквенно-цифровым.

Теперь, когда мы импортировали и сконфигурировали нашу контактную форму, мы можем использовать ее в отображении URL-адреса routes.py . Давайте продолжим и создадим это отображение URL.

Приложение / routes.py

1
2
3
4
@app.route(‘/contact’)
def contact():
  form = ContactForm()
  return render_template(‘contact.html’, form=form)

Теперь, когда кто-то посещает URL /contact , функция contact() будет выполняться. Внутри contact() мы сначала создаем новый экземпляр нашей контактной формы в третьей строке и отправляем его в веб-шаблон с именем contact.html в четвертой строке. Мы создадим этот веб-шаблон в ближайшее время.

У нас еще есть кое-что сделать здесь. На рисунке 1 показано, что если запрос GET отправляется на сервер, веб-страницу, содержащую форму, следует извлечь и загрузить в браузер. Если сервер получает запрос POST, функция должна захватить данные поля формы и проверить, действителен ли он. В терминах Python эта логика может быть выражена в операторе if...else . Существует класс Flask для различия между запросами GET и POST, поэтому давайте начнем с импорта этого класса в начале routes.py и добавим логику if...else в функцию contact() .

Приложение / routes.py

01
02
03
04
05
06
07
08
09
10
11
12
13
from flask import Flask, render_template, request
.
.
.
@app.route(‘/contact’, methods=[‘GET’, ‘POST’])
def contact():
  form = ContactForm()
 
  if request.method == ‘POST’:
    return ‘Form posted.’
 
  elif request.method == ‘GET’:
    return render_template(‘contact.html’, form=form)

Мы уже импортировали класс Flask и render_template() в предыдущей статье , поэтому здесь мы импортируем еще один класс Flask с именем request . request определяет, является ли текущий метод HTTP GET или POST. Далее следует логика if...else функции contact() (строки 9-13).

В случае запроса POST будет возвращена строка, указывающая, что форма была размещена.

Эта строка является временным заполнителем, и на последнем этапе этой статьи мы заменим ее реальным кодом. В противном случае, если запрос использует GET, мы возвращаем веб-шаблон contact.html который содержит форму.

Следующим шагом является создание веб-шаблона contact.html и его размещение в папке templates/ .

приложение / шаблоны / contact.html

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
{% extends «layout.html» %}
 
{% block content %}
  <h2>Contact</h2>
  <form action=»{{ url_for(‘contact’) }}» method=post>
    {{ form.hidden_tag() }}
 
    {{ form.name.label }}
    {{ form.name }}
 
    {{ form.email.label }}
    {{ form.email }}
 
    {{ form.subject.label }}
    {{ form.subject }}
 
    {{ form.message.label }}
    {{ form.message }}
 
    {{ form.submit }}
  </form>
{% endblock %}

Как и в about.html home.html и about.html , шаблон contact.html расширяет layout.html и заполняет блок ‘content’ собственным текстом. Сначала мы указываем, куда отправлять данные формы при отправке, устанавливая атрибут action элемента <form> для функции contact() мы создали в routes.py (строка пятая). Далее мы даем шаблонизатору Jinja2 сгенерировать большую часть формы для нас (строки 6-20). Мы начинаем со вставки скрытого тега в шестой строке, чтобы защитить от эксплойтов CSRF. Наконец, мы добавляем каждый ярлык и поле формы.

Теперь мы готовы увидеть результат всей нашей работы. Просто введите следующее:

1
$ python routes.py

Затем перейдите по адресу http: // localhost: 5000 / contact в вашем любимом веб-браузере.

Страница контактов, содержащая форму, загружена. Заполните поля формы и нажмите кнопку «Отправить». Вы увидите страницу, которая выглядит следующим образом:

Потрясающие! Форма отправки работает.

Давайте быстро рассмотрим все, что мы сделали в этом разделе:

  • Мы вводим URL-адрес http: // localhost: 5000 / contact в адресную строку браузера.
  • Запрос GET обращается к routes.py , где URL /contact сопоставляется с функцией contact() .
  • Функция contact() выполняется, когда переменная с именем form содержащая используемый экземпляр класса ContactForm отправляется в веб-шаблон contact.html .
  • contact.html генерирует HTML- contact.html контактной формы.
  • Визуализированный HTML- routes.py отправляется обратно routes.py .
  • routes.py отправляет HTML обратно в браузер, и мы видим контактную страницу, содержащую форму.
  • Заполняем контактную форму и отправляем ее, нажав кнопку «Отправить».
  • Запрос POST обращается к routes.py , где URL /contact отображается на функцию contact() .
  • Функция contact() выполняется еще раз, на этот раз в соответствии с потоком управления if...else для запроса HTTP POST.
  • Строка 'Form posted.' отправляется обратно в браузер, давая нам экран выше.

Контрольная точка: 05_contact_form

Это круто, но контактная форма выглядит некрасиво. Давайте сделаем его лучше, добавив немного CSS. Откройте main.css и добавьте эти правила:

Статическая / CSS / main.css

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* Contact form */
form label {
  font-size: 1.2em;
  font-weight: bold;
  display: block;
  padding: 10px 0;
}
 
form input#name,
form input#email,
form input#subject {
  width: 400px;
  background-color: #fafafa;
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
          border-radius: 3px;
  border: 1px solid #cccccc;
  padding: 5px;
  font-size: 1.1em;
}
 
form textarea#message {
  width: 500px;
  height: 100px;
  background-color: #fafafa;
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
          border-radius: 3px;
  border: 1px solid #cccccc;
  margin-bottom: 10px;
  padding: 5px;
  font-size: 1.1em;
}
 
form input#submit {
  display: block;
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
          border-radius: 3px;
  border:1px solid #d8d8d8;
  padding: 10px;
  font-weight:bold;
  text-align: center;
  color: #000000;
  background-color: #f4f4f4;
  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f4f4), color-stop(100%, #e5e5e5));
  background-image: -webkit-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: -moz-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: -ms-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: -o-linear-gradient(top, #f4f4f4, #e5e5e5);
  background-image: linear-gradient(top, #f4f4f4, #e5e5e5);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#f4f4f4, endColorstr=#e5e5e5);
}
 
form input#submit:hover{
  cursor: pointer;
  border:1px solid #c1c1c1;
  background-color: #dbdbdb;
  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#dbdbdb), color-stop(100%, #cccccc));
  background-image: -webkit-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: -moz-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: -ms-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: -o-linear-gradient(top, #dbdbdb, #cccccc);
  background-image: linear-gradient(top, #dbdbdb, #cccccc);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#dbdbdb, endColorstr=#cccccc);
}

Вернитесь в браузер и обновите http: // localhost: 5000 / contact, чтобы увидеть результат CSS.

Это выглядит намного лучше. Давайте перейдем к проверке формы.

Контрольная точка: 06_contact_styling

Теперь пользователь может посетить URL /contact и заполнить форму. Но что произойдет, если пользователь неправильно заполнит форму? Нам нужно проверить ввод пользователя, чтобы он не вызывал проблем на последующих этапах.

Проверка формы выполняется с использованием средств проверки формы. К счастью, Flask-WTF поставляется с множеством полезных встроенных валидаторов, которые мы можем использовать сразу. Мы поместим эти валидаторы в определение класса forms.py в forms.py .

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

Приложение / forms.py

1
2
3
4
5
6
7
8
from flask.ext.wtf import Form, TextField, TextAreaField, SubmitField, validators, ValidationError
 
class ContactForm(Form):
  name = TextField(«Name», [validators.Required()])
  email = TextField(«Email», [validators.Required()])
  subject = TextField(«Subject», [validators.Required()])
  message = TextAreaField(«Message», [validators.Required()])
  submit = SubmitField(«Send»)

Мы начнем с импорта validators и ValidationError из Flask-WTF. Это дает нам доступ к встроенным валидаторам Flask-WTF. Затем мы добавляем [validators.Required()] к каждому полю формы, чтобы проверить его наличие. Обратите внимание, что этот валидатор находится внутри списка Python, что означает, что мы можем легко добавить больше валидаторов в этот список.

Далее, давайте [email protected] адреса электронной почты соответствовать шаблону [email protected] , добавив в поле адреса электронной почты валидатор.

Приложение / forms.py

1
2
3
4
5
6
7
8
from flask.ext.wtf import Form, TextField, TextAreaField, SubmitField, validators, ValidationError
 
class ContactForm(Form):
  name = TextField(«Name», [validators.Required()])
  email = TextField(«Email», [validators.Required(), validators.Email()])
  subject = TextField(«Subject», [validators.Required()])
  message = TextAreaField(«Message», [validators.Required()])
  submit = SubmitField(«Send»)

Это делает это для нашей проверки формы.

Контрольная точка: 07_form_validations

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

Нашим следующим шагом будет отправка такого рода временного сообщения об ошибке пользователю при сбое проверки. Flask делает это действительно легко, используя функцию flash() . Давайте начнем с открытия routes.py и импорта функции flash() Flask в начале скрипта.

Приложение / routes.py

1
from flask import Flask, render_template, request, flash

После того, как контактная форма отправит запрос на сервер, любая ошибка проверки должна перезагрузить форму с полезным сообщением об ошибке. В противном случае входные данные могут быть использованы для дальнейшей обработки. Еще раз, эта логика может быть выражена в операторе if...else . Давайте добавим эту логику if...else в функцию contact() внутри блока if request.method == 'POST':

Приложение / routes.py

01
02
03
04
05
06
07
08
09
10
11
12
13
@app.route(‘/contact’, methods=[‘GET’, ‘POST’])
def contact():
  form = ContactForm()
 
  if request.method == ‘POST’:
    if form.validate() == False:
      flash(‘All fields are required.’)
      return render_template(‘contact.html’, form=form)
    else:
      return ‘Form posted.’
 
  elif request.method == ‘GET’:
    return render_template(‘contact.html’, form=form)

Если какая-либо проверка не form.validate() , form.validate() будет False . Сообщение об ошибке All fields are required будут отправлены в contact.html . В противном случае мы увидим строку Form posted заполнителя временного заполнителя, указывающую, что форма была успешно отправлена.

Далее, давайте contact.html чтобы он мог получать и отображать эти временные сообщения об ошибках. Смотрите следующий блок:

1
2
3
{% for message in get_flashed_messages() %}
  <div class=»flash»>{{ message }}</div>
{% endfor %}

Функция get_flashed_messages() извлекает все get_flashed_messages() сообщения и возвращает их. Затем мы просто отображаем каждое вспыхнувшее сообщение, используя цикл Jinja2 for . Добавьте этот блок кода в contact.html после <h2>Contact</h2> и перед <form> .

приложение / шаблоны / contact.html

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{% extends «layout.html» %}
 
{% block content %}
  <h2>Contact</h2>
 
  {% for message in get_flashed_messages() %}
    <div class=»flash»>{{ message }}</div>
  {% endfor %}
   
  <form action=»{{ url_for(‘contact’) }}» method=post>
    {{ form.hidden_tag() }}
 
    {{ form.name.label }}
    {{ form.name }}
 
    {{ form.email.label }}
    {{ form.email }}
 
    {{ form.subject.label }}
    {{ form.subject }}
 
    {{ form.message.label }}
    {{ form.message }}
 
    {{ form.submit }}
  </form>
{% endblock %}

Наконец, давайте добавим правило CSS в main.css чтобы сообщения об ошибках выглядели довольно привлекательно.

main.css

1
2
3
4
5
6
/* Message flashing */
.flash {
  background-color: #FBB0B0;
  padding: 10px;
  width: 400px;
}

Откройте ваш браузер и посетите http: // localhost: 5000 / contact . Оставьте все поля незаполненными и нажмите «Отправить», чтобы проверить, работают ли проверка формы и мигание сообщения об ошибке.

Это мило! Мы успешно отправили сообщение об ошибке в нашу контактную форму, если проверка не пройдена.

Контрольная точка: 08_error_message_flashing

Но мы еще не закончили; на самом деле мы можем сделать немного лучше. Вместо того, чтобы иметь одно общее сообщение об ошибке для всех неудачных проверок, было бы лучше иметь конкретное сообщение об ошибке для каждой неудачной проверки. Например, если пользователь забудет заполнить поле темы, будет отображено сообщение об ошибке « Please enter a subject . Аналогичным образом, если пользователь забудет Please enter your name , мы выскажем конкретное сообщение об ошибке « Please enter your name . Мы можем сделать это довольно легко, поэтому давайте начнем с написания наших конкретных сообщений об ошибках внутри каждого валидатора в forms.py .

Приложение / forms.py

1
2
3
4
5
6
7
8
from flask.ext.wtf import Form, TextField, TextAreaField, SubmitField, validators, ValidationError
 
class ContactForm(Form):
  name = TextField(«Name», [validators.Required(«Please enter your name.»)])
  email = TextField(«Email», [validators.Required(«Please enter your email address.»), validators.Email(«Please enter your email address.»)])
  subject = TextField(«Subject», [validators.Required(«Please enter a subject.»)])
  message = TextAreaField(«Message», [validators.Required(«Please enter a message.»)])
  submit = SubmitField(«Send»)

Мы просто пишем конкретные сообщения об ошибках внутри каждого валидатора. Далее давайте contact.html чтобы получать и отображать эти конкретные сообщения об ошибках. Ранее мы использовали функцию get_flashed_messages() для извлечения вспыхнувших сообщений об ошибках и их циклического отображения для отображения. Давайте заменим этот блок следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
{% for message in form.name.errors %}
  <div class=»flash»>{{ message }}</div>
{% endfor %}
 
{% for message in form.email.errors %}
  <div class=»flash»>{{ message }}</div>
{% endfor %}
 
{% for message in form.subject.errors %}
  <div class=»flash»>{{ message }}</div>
{% endfor %}
 
{% for message in form.message.errors %}
  <div class=»flash»>{{ message }}</div>
{% endfor %}

Здесь мы используем атрибут errors для каждого поля формы, чтобы вытянуть конкретные сообщения об ошибках и зациклить их, используя цикл Jinja2 for для их отображения.

Собрав все вместе, contact.html теперь выглядит так:

приложение / шаблоны / contact.html

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{% extends «layout.html» %}
 
{% block content %}
  <h2>Contact</h2>
 
  {% for message in form.name.errors %}
    <div class=»flash»>{{ message }}</div>
  {% endfor %}
 
  {% for message in form.email.errors %}
    <div class=»flash»>{{ message }}</div>
  {% endfor %}
 
  {% for message in form.subject.errors %}
    <div class=»flash»>{{ message }}</div>
  {% endfor %}
 
  {% for message in form.message.errors %}
    <div class=»flash»>{{ message }}</div>
  {% endfor %}
   
  <form action=»{{ url_for(‘contact’) }}» method=post>
    {{ form.hidden_tag() }}
 
    {{ form.name.label }}
    {{ form.name }}
 
    {{ form.email.label }}
    {{ form.email }}
 
    {{ form.subject.label }}
    {{ form.subject }}
 
    {{ form.message.label }}
    {{ form.message }}
 
    {{ form.submit }}
  </form>
{% endblock %}

Вернитесь в браузер, перейдите по адресу http: // localhost: 5000 / contact и нажмите «Отправить». Обязательно оставьте все поля формы пустыми.

Отлично! Теперь у пользователя есть полезные сообщения об ошибках, если он допустил ошибку.

Контрольная точка: 09_specific_message_flashing

Мы многого достигли в этом разделе. Мы создали контактную форму с нуля, научились защищать от CSRF-атак, различали запросы GET и POST, принудительно проверяли формы и при необходимости высвечивали специальные сообщения об ошибках. Теперь нам нужно отправить сообщение по электронной почте.


Flask-Mail — это расширение Flask, которое позволяет отправлять электронные письма из приложения Flask. Приведенные ниже шаги аналогичны тем, которые мы использовали для использования Flask-WTF.

Начнем с установки Flask-Mail.

1
$ pip install flask-mail

Далее, давайте импортируем Flask-Mail в routes.py и настроим его так, чтобы мы могли начать его использовать.

Приложение / routes.py

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
from flask import Flask, render_template, request, flash
from forms import ContactForm
from flask.ext.mail import Message, Mail
 
mail = Mail()
 
app = Flask(__name__)
 
app.secret_key = ‘development key’
 
app.config[«MAIL_SERVER»] = «smtp.gmail.com»
app.config[«MAIL_PORT»] = 465
app.config[«MAIL_USE_SSL»] = True
app.config[«MAIL_USERNAME»] = ‘[email protected]
app.config[«MAIL_PASSWORD»] = ‘your-password’
 
mail.init_app(app)

Сначала мы импортируем классы Message и Mail из Flask-Mail (третья строка). Мы будем использовать класс Message для создания нового электронного письма и класс Mail для отправки электронного письма. Затем мы создаем переменную mail которая содержит пригодный для использования экземпляр класса Mail (строка пятая).

Затем мы настраиваем Flask-Mail с несколькими настройками SMTP-сервера (строки 11-15). Я использовал настройки SMTP-сервера Gmail, но вы легко можете использовать своего любимого почтового провайдера. Просто найдите его настройки SMTP и все будет готово.

Например, если вы хотите использовать Yahoo! Почта, просто найдите «Настройки сервера Yahoo Mail SMTP» и обновите конфигурацию.

Обязательно введите реальный адрес электронной почты и пароль в app.config["MAIL_USERNAME"] и app.config["MAIL_PASSWORD"] , соответственно. Это будет учетная запись, с которой вы будете отправлять электронную почту.

Наконец, мы прикрепляем mail к нашему приложению Flask, чтобы начать ее использовать (строка 17).

Возможно, вы видели, как группы используют контактные адреса электронной почты, например [email protected] или [email protected] . Если у вас есть собственный домен и вы можете создать новый контактный адрес электронной почты, app.config["MAIL_USERNAME"] этот адрес электронной почты в app.config["MAIL_USERNAME"] . В противном случае, вы можете использовать свой личный адрес электронной почты, просто чтобы посмотреть, как это работает.

Теперь, когда настройка завершена, давайте составим новое электронное письмо, содержащее данные контактной формы, и отправим его. Мы должны отправлять электронное письмо только в том случае, если форма была отправлена ​​и все проверки достоверности пройдены. Это означает, что нам нужно снова работать внутри блока if request.method == 'POST': . Мы уже добавили логику в if form.validate() == False: для обработки ошибок проверки. Если все проверки правильности form.validate() , form.validate() будет True и программа войдет в блок else . Поэтому давайте продолжим и добавим логику в блок else:

Приложение / routes.py

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@app.route(‘/contact’, methods=[‘GET’, ‘POST’])
def contact():
  form = ContactForm()
 
  if request.method == ‘POST’:
    if form.validate() == False:
      flash(‘All fields are required.’)
      return render_template(‘contact.html’, form=form)
    else:
      msg = Message(form.subject.data, sender=’[email protected]’, recipients=[‘[email protected]’])
      msg.body = «»»
      From: %s <%s>
      %s
      «»» % (form.name.data, form.email.data, form.message.data)
      mail.send(msg)
 
      return ‘Form posted.’
 
  elif request.method == ‘GET’:
    return render_template(‘contact.html’, form=form)

Мы начинаем с составления нового сообщения (строка 10). Класс Message принимает строку темы, адрес «from» и адрес «to». Затем мы собираем данные поля темы контактной формы с помощью form.subject.data и устанавливаем его как строку темы нового сообщения. Письмо будет отправлено с учетной записи, которую вы настроили в app.config["MAIL_USERNAME"] , так что именно это мы и использовали здесь для адреса от. Письмо будет отправлено на ваш личный адрес электронной почты, чтобы вы могли получать и отвечать на новые сообщения.

Далее мы пишем само письмо (строки 11-14). Мы включаем имя пользователя, адрес электронной почты и сообщение. Я использую оператор форматирования строки Python % для форматирования электронной почты. И, наконец, мы используем mail.send(msg) для отправки электронного письма (строка 15).

Посмотрим, все ли работает. Посетите http: // localhost: 5000 / contact , заполните каждое поле и нажмите «Отправить». Если все пойдет хорошо, вы получите новое электронное письмо от вашего приложения Flask.

Контрольная точка: 10_send_email

Наш предпоследний шаг — удалить строку временного заполнителя 'Form posted.' с сообщением, поблагодарив пользователя за отзыв. Это сообщение должно появляться только в том случае, если наше приложение отправляет электронное письмо. Еще раз, эта логика может быть выражена в операторе if...else .

После того, как контактная форма была успешно отправлена, мы отправим флаг успеха из routes.py в contact.html .

Мы разместим логику if...else внутри contact.html . Если флаг успеха установлен в True , мы отобразим сообщение с благодарностью. В противном случае мы отобразим контактную форму.

Давайте начнем с routes.py в routes.py внутри функции contact() . Замените временную строку-заполнитель на return 'Form posted.' с return render_template('contact.html', success=True) для отправки флага успеха в contact.html . Функция contact() теперь выглядит так:

Приложение / routes.py

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@app.route(‘/contact’, methods=[‘GET’, ‘POST’])
def contact():
  form = ContactForm()
 
  if request.method == ‘POST’:
    if form.validate() == False:
      flash(‘All fields are required.’)
      return render_template(‘contact.html’, form=form)
    else:
      msg = Message(form.subject.data, sender=’[email protected]’, recipients=[‘[email protected]’])
      msg.body = «»»
      From: %s &lt;%s&gt;
      %s
      «»» % (form.name.data, form.email.data, form.message.data)
      mail.send(msg)
 
      return render_template(‘contact.html’, success=True)
 
  elif request.method == ‘GET’:
    return render_template(‘contact.html’, form=form)

Затем откройте contact.html и добавьте логику if...else . Мы будем использовать синтаксис Jinja2 if...else чтобы это произошло.

приложение / шаблоны / contact.html

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{% extends «layout.html» %}
 
{% block content %}
  <h2>Contact</h2>
 
  {% if success %}
    <p>Thank you for your message.
 
  {% else %}
 
    {% for message in form.name.errors %}
      <div class=»flash»>{{ message }}</div>
    {% endfor %}
 
    {% for message in form.email.errors %}
      <div class=»flash»>{{ message }}</div>
    {% endfor %}
 
    {% for message in form.subject.errors %}
      <div class=»flash»>{{ message }}</div>
    {% endfor %}
 
    {% for message in form.message.errors %}
      <div class=»flash»>{{ message }}</div>
    {% endfor %}
 
    <form action=»{{ url_for(‘contact’) }}» method=post>
      {{ form.hidden_tag() }}
 
      {{ form.name.label }}
      {{ form.name }}
 
      {{ form.email.label }}
      {{ form.email }}
 
      {{ form.subject.label }}
      {{ form.subject }}
 
      {{ form.message.label }}
      {{ form.message }}
 
      {{ form.submit }}
    </form>
 
  {% endif %}
{% endblock %}

Начиная с шестой строки, {% if success %} означает, что если для флага успеха, который мы отправили из routes.py , задано значение True , отобразится <p>Thank you for your message. We'll get back to you shortly.</p> <p>Thank you for your message. We'll get back to you shortly.</p> . В противном случае следуйте ветке {% else %} и отобразите форму контакта. Синтаксис Jinja2 требует, чтобы мы закрыли оператор if...else с помощью {% endif %} , поэтому мы включаем его в конец (строка 45).

Контрольная точка: 11_success_message

Наконец, давайте еще раз посетим http: // localhost: 5000 / contact . Заполните каждое поле и нажмите «Отправить».

Наш последний шаг — добавить навигационную ссылку на страницу контактов. В предыдущей статье мы добавили эти ссылки на layout.html внутри элемента <header> . Давайте также сделаем это для страницы контактов (строка восемь).

приложение / шаблоны / layout.html

01
02
03
04
05
06
07
08
09
10
11
12
<header>
  <div class=»container»>
    <h1 class=»logo»>Flask App</h1>
    <nav>
      <ul class=»menu»>
        <li><a href=»{{ url_for(‘home’) }}»>Home</a></li>
        <li><a href=»{{ url_for(‘about’) }}»>About</a></li>
        <li><a href=»{{ url_for(‘contact’) }}»>Contact</a></li>
      </ul>
    </nav>
  </div>
</header>

Контрольная точка: 12_contact_nav_link

Откройте браузер и обновите http: // localhost: 5000 /, чтобы увидеть недавно добавленную навигационную ссылку.


В статье мы добавили страницу контактов, которая содержит форму для нашего приложения Flask. Формы появляются в нескольких местах в веб-приложениях, особенно во время регистрации и входа в систему. Этот рабочий процесс может быть адаптирован для удовлетворения этих потребностей. Создавая страницу контактов, мы узнали, как использовать расширения Flask.

Расширения Flask — это простые, мощные инструменты, расширяющие функциональность вашего приложения на основе Flask.

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