Главная | Архив новостей | Общение | Площадка | Примеры OpenID
Хостинг Django от «Джино»
Оглавление

Создание формы для контактной информации

Несмотря на то, что мы несколько раз изменяли форму поиска по книгам и значительно её улучшили, она осталась достаточно простой: просто одно поле, q. Из-за её простоты мы даже не воспользовались библиотекой форм Django. Более сложные формы потребуют более сложную обработку — сделаем что-нибудь посложнее: форму для передачи контактной информации.

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

Начнём с шаблона, contact_form.html:

<html>
<head>
    <title>Contact us</title>
</head>
<body>
    <h1>Contact us</h1>

    {% if errors %}
        <ul>
            {% for error in errors %}
            <li>{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}

    <form action="/contact/" method="post">
        <p>Subject: <input type="text" name="subject"></p>
        <p>Your e-mail (optional): <input type="text" name="email"></p>
        <p>Message: <textarea name="message" rows="10" cols="50"></textarea></p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

Мы определили три поля: заголовок, адрес электронной почты и сообщение. Второе поле необязательное. Следует отметить, что мы используем method="post", так как форма имеет сторонний эффект (side effect FIXME) — она отправляет сообщение. Также мы скопировали код, отвечающий за отображение ошиюки из нашего предыдущего шаблона search_form.html.

Если продолжать методику, начатую при работе с нашим представлением search(), первой наивной версией нашего представления contact() будет:

from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response

def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e-mail address.')
        if not errors:
            send_mail(
                request.POST['subject'],
                request.POST['message'],
                request.POST.get('email', 'noreply@example.com'),
                ['siteowner@example.com'],
            )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html',
        {'errors': errors})

(Если вы сразу проверяете наш код в действии, вы можете заинтересоваться зачем размещать это представление в файле books/views.py. Оно предназначено для работы с книжным приложением, где же ему ещё находиться? Но в общем, всё зависит от вас. Django нет разницы где размещён код, если она может найти его по связи в URL. Мы предпочитаем создавать отдельный каталог, contact на уровне каталога books Он будет содержать пустой __init__.py и views.py.)

Рассмотрим отличия:

  • Мы проверяем, что request.method равен 'POST'. Это условие будет верным только в случае отправки формы, иначе считаем, что происходит простое отображение формы. (В последнем случае, request.method будет установлен в 'GET', так как для отображения формы браузеры используют GET, а не POST.) Такой подход обеспечивает отличный способ изоляции случая «отображения формы» от «обработки формы».

  • Вместо использования request.GET мы применяем request.POST для доступа к переданным данным. Это необходимо, так как <form> в contact_form.html использует method="post". Если данное представление вызывается через POST, значит request.GET будет пустым.

  • В этот раз у нас есть два обязательных поля, subject и message, нам следует проверять оба. Следует отметить, что для получения значения из POST мы используем метод get() и подставляем пустую строку в качестве значения по умолчанию. Это хорошим, краткий способ обработки двух проблем: отсутствие ключа и отсутствие данных.

  • Несмотря на то, что поле email является необязательным, мы всё равно проверяем его, правда только при наличии в нём данных. Наша проверка достаточно простая — мы проверяем наличие в строке символа @. В реальной ситуации вам потребуется более устойчивая проверка (и Django предоставляет её, мы очень скоро её покажем).

  • Мы используем функцию send_mail из модуля django.core.mail для отправки сообщения по электронной почте. Эта функция принимает четыре обязательных аргумента: тема сообщения, тело сообщения, адрес «от» и список адресов получателей. Функция send_mail является удобной оболочкой над классом Django EmailMessage, который предоставляет дополнительные возможности, например, вложение файлов, multipart сообщения и полный контроль над заголовками сообщения.

    Следует отметить, что для отправки сообщения с помощью send_mail ваш сервер должен быть соответственно сконфигуриров и Django следует указать на сервер исходящей почты. Обратитесь к http://docs.djangoproject.com/en/dev/topics/email/ для подробностей.

  • После отправки сообщения мы перенаправляем пользователя на страницу с сообщением об успешном выполнении операции, возвращая объект HttpResponseRedirect. Мы оставляем реализацию такой страницы вам в качестве домашнего задания (это просто представление/привязка URL/шаблон), но нам следует объяснить причину, почему мы инициировали перенаправление вместо, например, простого вызова render_to_response() прямо здесь.

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

    Вы всегда должны осуществлять перенаправление после успешной обработки POST запроса.

Данное представление работает, но представьте, что вам придётся обработать форму с дюжиной полей. Вы действительно желаете самостоятельно расписывать проверки для каждого поля?

Следующей проблемой является повторное отображение формы. В случае возникновения ошибок при проверке полей, лучше всего будет отобразить форму повторно, внеся в поля переданные данные, так пользователь сможет увидеть, что именно он сделал неправильно (и также ему не потребуется вводить эти данные повторно). Мы можем вручную передать POST данные обратно в шаблон, но нам потребуется отредактировать каждое HTML поле для вставки соответствующего значения на соответствующее место.

views.py:

def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject.')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e-mail address.')
        if not errors:
            send_mail(
                request.POST['subject'],
                request.POST['message'],
                request.POST.get('email', 'noreply@example.com'),
                ['siteowner@example.com'],
            )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html', {
        'errors': errors,
        'subject': request.POST.get('subject', ''),
        'message': request.POST.get('message', ''),
        'email': request.POST.get('email', ''),
    })

contact_form.html:

<html>
<head>
    <title>Contact us</title>
</head>
<body>
    <h1>Contact us</h1>

    {% if errors %}
        <ul>
            {% for error in errors %}
            <li>{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}

    <form action="/contact/" method="post">
        <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
        <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p>
        <p>Message: <textarea name="message" rows="10" cols="50">**{{ message }}**</textarea></p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

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


Увидели ошибку?
Выделите её мышкой и нажмите
Ctrl-Enter
Обработано:
1049 49 130 71

Версия книги
1.0 2.0
Версия 2.0 в процессе перевода!

Мой луч
Многообразие света

Полезное
Актуальные вакансии, Python работа для python-разработчиков.


Скачать в формате
CHM от 2 сентября

Заказать PDF файл можно через почту, чат, джаббер. Всего 2WMZ. Содержимое точно соответствует содержимому сайта.
Чем чаще заказываете — тем больше перевожу.

Русская группа

на поддержку перевода
Яндекс Яндекс.Деньги Хочу такую же кнопку
Ускорить процесс перевода!
R130494980980
Z425285133788
E112528079659
U327380922061

Книга помогла реализовать:
Проект «Мой луч»
АРМ УФМС.


Мой вебсайт стоит666 337,31 руб

© 2008-2009 Ruslan Popov @ gmail.com Powered by Django 1.1 beta 1 SVN-11114
Главная | Архив новостей | Общение | Площадка | Примеры OpenID