在Django框架中编写Contact表单的教程


Posted in Python onJuly 17, 2015

虽然我们一直使用书籍搜索的示例表单,并将起改进的很完美,但是这还是相当的简陋: 只包含一个字段,q。这简单的例子,我们不需要使用Django表单库来处理。 但是复杂一点的表单就需要多方面的处理,我们现在来一下一个较为复杂的例子: 站点联系表单。

这个表单包括用户提交的反馈信息,一个可选的e-mail回信地址。 当这个表单提交并且数据通过验证后,系统将自动发送一封包含题用户提交的信息的e-mail给站点工作人员。

我们从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>

我们定义了三个字段: 主题,e-mail和反馈信息。 除了e-mail字段为可选,其他两个字段都是必填项。 注意,这里我们使用method=”post”而非method=”get”,因为这个表单会有一个服务器端的操作:发送一封e-mail。 并且,我们复制了前一个模板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})

(如果按照书中的示例做下来,这这里可能乎产生一个疑问:contact()视图是否要放在books/views.py这个文件里。 但是contact()视图与books应用没有任何关联,那么这个视图应该可以放在别的地方? 这毫无紧要,只要在URLconf里正确设置URL与视图之间的映射,Django会正确处理的。 笔者个人喜欢创建一个contact的文件夹,与books文件夹同级。这个文件夹中包括空的__init__.py和views.py两个文件。

现在来分析一下以上的代码:

    确认request.method的值是'POST'。用户浏览表单时这个值并不存在,当且仅当表单被提交时这个值才出现。 (在后面的例子中,request.method将会设置为'GET',因为在普通的网页浏览中,浏览器都使用GET,而非POST)。判断request.method的值很好地帮助我们将表单显示与表单处理隔离开来。

    我们使用request.POST代替request.GET来获取提交过来的数据。 这是必须的,因为contact_form.html里表单使用的是method=”post”。如果在视图里通过POST获取数据,那么request.GET将为空。

    这里,有两个必填项,subject 和 message,所以需要对这两个进行验证。 注意,我们使用request.POST.get()方法,并提供一个空的字符串作为默认值;这个方法很好的解决了键丢失与空数据问题。

    虽然email非必填项,但如果有提交她的值则我们也需进行验证。 我们的验证算法相当的薄弱,仅验证值是否包含@字符。 在实际应用中,需要更为健壮的验证机制(Django提供这些验证机制,稍候我们就会看到)。

    我们使用了django.core.mail.send_mail函数来发送e-mail。 这个函数有四个必选参数: 主题,正文,寄信人和收件人列表。 send_mail是Django的EmailMessage类的一个方便的包装,EmailMessage类提供了更高级的方法,比如附件,多部分邮件,以及对于邮件头部的完整控制。

    注意,若要使用send_mail()函数来发送邮件,那么服务器需要配置成能够对外发送邮件,并且在Django中设置出站服务器地址。 参见规范:http://docs.djangoproject.com/en/dev/topics/email/

    当邮件发送成功之后,我们使用HttpResponseRedirect对象将网页重定向至一个包含成功信息的页面。 包含成功信息的页面这里留给读者去编写(很简单 一个视图/URL映射/一份模板即可),但是我们要解释一下为何重定向至新的页面,而不是在模板中直接调用render_to_response()来输出。

    原因就是: 若用户刷新一个包含POST表单的页面,那么请求将会重新发送造成重复。 这通常会造成非期望的结果,比如说重复的数据库记录;在我们的例子中,将导致发送两封同样的邮件。 如果用户在POST表单之后被重定向至另外的页面,就不会造成重复的请求了。

    我们应每次都给成功的POST请求做重定向。 这就是web开发的最佳实践。

contact()视图可以正常工作,但是她的验证功能有些复杂。 想象一下假如一个表单包含一打字段,我们真的将必须去编写每个域对应的if判断语句?

另外一个问题是表单的重新显示。若数据验证失败后,返回客户端的表单中各字段最好是填有原来提交的数据,以便用户查看哪里出现错误(用户也不需再次填写正确的字段值)。 我们可以手动地将原来的提交数据返回给模板,并且必须编辑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>

这看起来杂乱,且写的时候容易出错。 希望你开始明白使用高级库的用意——负责处理表单及相关校验任务。

Python 相关文章推荐
基于Python实现的扫雷游戏实例代码
Aug 01 Python
python中的多线程实例教程
Aug 27 Python
Python中使用插入排序算法的简单分析与代码示例
May 04 Python
Python中functools模块函数解析
Mar 12 Python
使用Python的turtle模块画图的方法
Nov 15 Python
Django 使用Ajax进行前后台交互的示例讲解
May 28 Python
利用python、tensorflow、opencv、pyqt5实现人脸实时签到系统
Sep 25 Python
python3中的eval和exec的区别与联系
Oct 10 Python
python实现在线翻译功能
Mar 03 Python
jupyter 使用Pillow包显示图像时inline显示方式
Apr 24 Python
python批量生成条形码的示例
Oct 10 Python
Python 操作SQLite数据库的示例
Oct 16 Python
简单解析Django框架中的表单验证
Jul 17 #Python
改进Django中的表单的简单方法
Jul 17 #Python
Python的Django框架中的表单处理示例
Jul 17 #Python
Python中max函数用法实例分析
Jul 17 #Python
详解Django中Request对象的相关用法
Jul 17 #Python
Python实现SVN的目录周期性备份实例
Jul 17 #Python
Python的Django框架中设置日期和字段可选的方法
Jul 17 #Python
You might like
PHP 数组遍历方法大全(foreach,list,each)
2010/06/30 PHP
php生成图形(Libchart)实例
2013/11/06 PHP
js动态给table添加/删除tr的方法
2013/08/02 Javascript
jQuery实现图片信息的浮动显示实例代码
2013/08/28 Javascript
JS图片无缝、平滑滚动代码
2014/03/11 Javascript
jquery datepicker参数介绍和示例
2014/04/15 Javascript
将数字转换成大写的人民币表达式的js函数
2014/09/21 Javascript
浅谈JavaScript中运算符的优先级
2015/07/07 Javascript
jQuery on()绑定动态元素出现的问题小结
2016/02/19 Javascript
JavaScript学习笔记之数组去重
2016/03/23 Javascript
jQuery中常用动画效果函数(日常整理)
2016/09/17 Javascript
jQuery实现输入框邮箱内容自动补全与上下翻动显示效果【附demo源码下载】
2016/09/20 Javascript
在网页中插入百度地图的步骤详解
2016/12/02 Javascript
vue-cli3环境变量与分环境打包的方法示例
2019/02/18 Javascript
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
2019/07/20 Javascript
three.js 制作动态二维码的示例代码
2020/07/31 Javascript
JavaScript 防抖和节流遇见的奇怪问题及解决
2020/11/20 Javascript
如何利用JavaScript编写一个格斗小游戏
2021/01/06 Javascript
[03:52]显微镜下的DOTA2第三期——英雄在无聊的时候干什么
2014/06/20 DOTA
[01:08:33]OG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python中合并两个文本文件并按照姓名首字母排序的例子
2014/04/25 Python
简单使用Python自动生成文章
2014/12/25 Python
django 发送手机验证码的示例代码
2018/04/25 Python
python调用xlsxwriter创建xlsx的方法
2018/05/03 Python
windows下安装Python的XlsxWriter模块方法
2018/05/03 Python
Python趣味入门教程之循环语句while
2020/08/26 Python
pytorch简介
2020/11/11 Python
个人自我评价分享
2013/12/20 职场文书
市优秀教师事迹材料
2014/02/05 职场文书
公司离职证明范本(汇总)
2014/09/10 职场文书
大学生入党积极分子自我评价
2014/09/20 职场文书
地方白酒代理协议书
2014/10/25 职场文书
旗帜观后感
2015/06/08 职场文书
工作自我评价范文
2019/03/21 职场文书
Vue自定义铃声提示音组件的实现
2022/01/22 Vue.js
mysql sql常用语句大全
2022/06/21 MySQL