《Django By Example》第二章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example
原作者:Antonio Melé
2016年12月13日发布(3天完成第二章的翻译,但没有进行校对,有很多错别字以及模糊不清的语句,请大家见谅)
2017年2月17日校对完成(不是精校,希望大家多指出需要修改的地方)
2017年3月6日精校完成(感谢大牛 @kukoo 的精校!)
2017年3月21日再度精校(感谢大牛 @妈妈不在家 的精校!初版我已经不敢再看!)
(译者注:翻译完第一章后,发现翻译第二章的速度上升了不少,难道这就是传说中的经验值提升了?)
第二章
用高级特性来增强你的blog
在上一章中,你创建了一个基础的博客应用。现在你将利用一些高级的特性例如通过email来分享帖子,添加评论,给帖子打上tag,检索出相似的帖子等将它改造成为一个功能更加齐全的博客。在本章中,你将会学习以下几点:
- 通过Django发送email
- 在视图(views)中创建并操作表单
- 通过模型(models)创建表单
- 集成第三方应用
- 构建复杂的查询集(QuerySets)
通过email分享帖子
首先,我们会允许用户通过发送邮件来分享他们的帖子。让我们花费一小会时间来想下,根据在上一章中学到的知识,你该如何使用views,urls和templates来创建这个功能。现在,核对一下你需要哪些才能允许你的用户通过邮件来发送帖子。你需要做到以下几点:
- 给用户创建一个表单来填写他们的姓名,email,收件人以及评论,评论不是必选项。
- 在views.py文件中创建一个视图(view)来操作发布的数据和发送email
- 在blog应用的urls.py中为新的视图(view)添加一个URL模式
- 创建一个模板(template)来展示这个表单
使用Django创建表单
让我们开始创建一个表单来分享帖子。Django有一个内置的表单框架允许你通过简单的方式来创建表单。这个表单框架允许你定义你的表单字段,指定这些字段必须展示的方式,以及指定这些字段如何验证输入的数据。Django表单框架还提供了一种灵活的方式来渲染表单以及操作数据。
Django提供了两个可以创建表单的基本类:
- Form: 允许你创建一个标准表单
- ModelForm: 允许你创建一个可用于创建或者更新model实例的表单
首先,在你blog应用的目录下创建一个forms.py文件,输入以下代码:
from django import forms
class EmailPostForm(forms.Form):
name = forms.CharField(max_length=25)
email = forms.EmailField()
to = forms.EmailField()
comments = forms.CharField(required=False,
widget=forms.Textarea)
这是你的第一个Django表单。看下代码:我们已经创建了一个继承了基础Form类的表单。我们使用不同的字段类型以使Django有依据的来验证字段。
表单可以存在你的Django项目的任何地方,但按照惯例将它们放在每一个应用下面的forms.py文件中
name字段是一个CharField。这种类型的字段被渲染成<input type=“text”>HTML元素。每种字段类型都有默认的控件来确定它在HTML中的展示形式。通过改变控件的属性可以重写默认的控件。在comment字段中,我们使用<textarea></textarea>HTML元素而不是使用默认的<input>元素来显示它。
字段验证取决于字段类型。例如,email和to字段是EmailField,这两个字段都需要一个有效的email地址,否则字段验证将会抛出一个forms.ValidationError异常导致表单验证不通过。在表单验证的时候其他的参数也会被考虑进来:我们将name字段定义为一个最大长度为25的字符串;通过设置required=False让comments的字段可选。所有这些也会被考虑到字段验证中去。目前我们在表单中使用的这些字段类型只是Django支持的表单字段的一部分。要查看更多可利用的表单字段,你可以访问:https://docs.djangoproject.com/en/1.8/ref/forms/fields/
在视图(views)中操作表单
当表单成功提交后你必须创建一个新的视图(views)来操作表单和发送email。编辑blog应用下的views.py文件,添加以下代码:
from .forms import EmailPostForm
def post_share(request, post_id):
# retrieve post by id
post = get_object_or_404(Post, id=post_id, status='published')
if request.method == 'POST':
# Form was submitted
form = EmailPostForm(request.POST)
if form.is_valid():
# Form fields passed validation
cd = form.cleaned_data
# ... send email
else:
form = EmailPostform()
return render(request, 'blog/post/share.html', {'post': post,
'form: form})
该视图(view)完成了以下工作:
- 我们定义了post_share视图,参数为request对象和post_id。
- 我们使用get_object_or_404快捷方法通过ID获取对应的帖子,并且确保获取的帖子有一个published状态。
- 我们使用同一个视图(view)来展示初始表单和处理提交后的数据。我们会区别被提交的表单和不基于这次请求方法的表单。我们将使用POST来提交表单。如果我们得到一个GET请求,一个空的表单必须显示,而如果我们得到一个POST请求,则表单需要提交和处理。因此,我们使用
request.method == 'POST'来区分这两种场景。
下面是展示和操作表单的过程:
-
1.通过GET请求视图(view)被初始加载后,我们创建一个新的表单实例,用来在模板(template)中显示一个空的表单:
form = EmailPostForm()
-
2.当用户填写好了表单并通过POST提交表单。之后,我们会用保存在
request.POST中提交的数据创建一个表单实例。if request.method == 'POST':
# Form was submitted
form = EmailPostForm(request.POST) -
3.在以上步骤之后,我们使用表单的is_valid()方法来验证提交的数据。这个方法会验证表单引进的数据,如果所有的字段都是有效数据,将会返回True。一旦有任何一个字段是无效的数据,is_valid()就会返回False。你可以通过访问
form.errors来查看所有验证错误的列表。 -
4如果表单数据验证没有通过,我们会再次使用提交的数据在模板(template)中渲染表单。我们会在模板(template)中显示验证错误的提示。
-
5.如果表单数据验证通过,我们通过访问
form.cleaned_data获取验证过的数据。这个属性是一个表单字段和值的字典。
如果你的表单数据没有通过验证,cleaned_data只会包含验证通过的字段
现在,你需要学习如何使用Django来发送email,把所有的事情结合起来。
使用Django发送email
使用Django发送email非常简单。首先,你需要有一个本地的SMTP服务或者通过在你项目的settings.py文件中添加以下设置去定义一个外部SMTP服务器的配置:
- EMAIL_HOST: SMTP服务地址。默认本地。
- EMAIL_POSR: SMATP服务端口,默认25。
- EMAIL_HOST_USER: SMTP服务的用户名。
- EMAIL_HOST_PASSWORD: SMTP服务的密码。
- EMAIL_USE_TLS: 是否使用TLS加密连接。
- EMAIL_USE_SSL: 是否使用隐式的SSL加密连接。
如果你没有本地SMTP服务,你可以使用你的email服务供应商提供的SMTP服务。下面提供了一个简单的例子展示如何通过使用Google账户的Gmail服务来发送email:
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'your_account@gmail.com'
EMAIL_HOST_PASSWORD = 'your_password'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
运行命令python manage.py shell来打开Python shell,发送一封email如下所示:
>>> from django.core.mail import send_mail
>>> send_mail('Django mail', 'This e-mail was sent with Django.','your_account@gmail.com', ['your_account@gmail.com'], fail_silently=False)
send_mail()方法需要这些参数:邮件主题,内容,发送人以及一个收件人的列表。通过设置可选参数fail_silently=False,我们告诉这个方法如果email没有发送成功那么需要抛出一个异常。如果你看到输出是1,证明你的email发送成功了。如果你使用之前的配置用Gmail来发送邮件,你可能需要去 https://www.google.com/settings/security/lesssecureapps 去开通一下低安全级别应用的权限。(译者注:练习时老老实实用QQ邮箱吧)
现在,我们要将以上代码添加到我们的视图(view)中。在blog应用下的views.py文件中编辑post_share视图(view)如下所示:
from django.core.mail import send_mail
def post_share(request, post_id):
# Retrieve post by id
post = get_object_or_404(Post, id=post_id, status='published')
sent = False
if request.method == 'POST':
# Form was submitted
form = EmailPostForm(request.POST)
if form.is_valid():
# Form fields passed validation
cd = form.cleaned_data
post_url = request.build_absolute_uri(
post.get_absolute_url())
subject = '{} ({}) recommends you reading "{}"'.format(cd['name'], cd['email'], post.title)
message = 'Read "{}" at {}\n\n{}\'s comments: {}'.format(post.title, post_url, cd['name'], cd['comments'])
send_mail(subject, message, 'admin@myblog.com',[cd['to']])
sent = True
else:
form = EmailPostForm()
return render(request, 'blog/post/share.html', {'post': post,
'form': form,
'sent': sent})
请注意,我们声明了一个sent变量并且当帖子被成功发送时赋予它True。当表单成功提交的时候,我们之后将在模板(template)中使用这个变量显示一条成功提示。由于我们需要在email中包含帖子的超链接,所以我们通过使用post.get_absolute_url()方法来获取到帖子的绝对路径。我们将这个绝对路径作为request.build_absolute_uri()的输入值来构建一个完整的包含了HTTP schema和主机名的url。我们通过使用验证过的表单数据来构建email的主题和消息内容并最终给表单to字段中包含的所有email地址发送email。
现在你的视图(view)已经完成了,别忘记为它去添加一个新的URL模式。打开你的blog应用下的urls.py文件添加post_share的URL模式如下所示:
urlpatterns = [
# ...
url(r'^(?P<post_id>\d+)/share/$', views.post_share,
name='post_share'),
]
在模板(templates)中渲染表单
在通过创建表单,编写视图(view)以及添加URL模式后,我们就只剩下为这个视图(view)添加模板(tempalte)了。在blog/templates/blog/post/目录下创建一个新的文件并命名为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 {{ cd.to }}.
</p>
{% else %}
<h1>Share "{{ post.title }}" by e-mail</h1>
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Send e-mail">
</form>
{% endif %}
{% endblock %}
这个模板(tempalte)专门用来显示一个表单或一条成功提示信息。如你所见,我们创建的HTML表单元素里面表明了它必须通过POST方法提交:

浙公网安备 33010602011771号