先添加几个页面,让用户输入数据。
首先,让用户可以添加新主题。方法于之前类似:定义URL,编写views和models,区别在于需要导入包含表单的模块forms.py。
1、创建forms.py,保存到models.py所在的目录中。
forms.py
from django import forms
form models import Topic
❶ class TopicForm(forms.ModelForm):
class Meta:
❷ model = Topic
❸ fields = ['text']
❹ labels = {'text': ''}
定义了一个名为TopicForm 的类,它继承了forms.ModelForm。最简单的ModelForm 版本只包含一个内嵌的Meta 类,让Django根据哪个模型创建表单以及在表单中包含哪些字段。在❷处,根据模型Topic 创建表单,其中只包含字段text (见❸)。❹处的代码让Django不要为字段text 生成标签。
2、定义urls
urls.py
urlpatterns = [
#-snip-
#添加新主题页面
path('new_topic/', views.new_topic,name='new_topic')
#-snip-
这个URL模式将请求交给下方编辑的视图函数new_topic()
3、views.py中定义视图函数new_topic
views.py
from django.shortcuts import render, redirect
from .models import Topic
from .forms import TopicForm
--snip--
def new_topic(request):
"""添加新主题。"""
❶ if request.method != 'POST':
# 未提交数据:创建一个新表单。
❷ form = TopicForm()
else:
# POST提交的数据:对数据进行处理。
❸ form = TopicForm(data=request.POST)
❹ if form.is_valid():
❺ form.save()
❻ return redirect('learning_logs:topics')
# 显示空表单或指出表单数据无效。
❼ context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
我们导入了函数redirect ,用户提交主题后将使用这个函数重定向到页面topics 。函数redirect 将视图名作为参数,并将用户重定向到这个视图。我们还导入了刚创建的表单TopicForm 。
创建Web应用程序时,将用到的两种主要请求类型是GET请求和POST请求。对于只是从服务器读取数据的页面,使用GET 请求;在用户需要通过表单提交信息时,通常使用POST 请求。处理所有表单时,都将指定使用POST方法。还有一些其他类型的请求,但本项目没有使用。
函数new_topic() 将请求对象作为参数。用户初次请求该页面时,其浏览器将发送GET请求;用户填写并提交表单时,其浏览器将发送POST请求。根据请求的类型,可确定用户请求的是空表单
(GET请求)还是要求对填写好的表单进行处理(POST请求)。
❶处的测试确定请求方法是GET还是POST。如果请求方法不是POST,请求就可能是GET,因此需要返回一个空表单。(即便请求是其他类型的,返回空表单也不会有任何问题。)❷处创建一个TopicForm 实例,将其赋给变量form ,再通过上下文字典将这个表单发送给模板(见❼)。由于实例化TopicForm 时没有指定任何实参,Django将创建一个空表单,供用户填写。
如果请求方法为POST,将执行else 代码块,对提交的表单数据进行处理。我们使用用户输入的数据(存储在request.POST 中)创建一个TopicForm 实例(见❸),这样对象form 将包含用户提交的信息。
要将提交的信息保存到数据库,必须先通过检查确定它们是有效的(见❹)。方法is_valid() 核实用户填写了所有必不可少的字段(表单字段默认都是必不可少的),且输入的数据与要求的字段类型一致(例如,字段text 少于200字符,在models.py中所指定的)。这种自动验证避免了我们去做大量的工作。如果所有字段都有效,就可调用save() (见❺),将表单中的数据写入数据库。
保存数据后,就可离开这个页面了。为此,使用redirect() 将用户的浏览器重定向到页面topics (见❻)。在页面topics 中,用户将在主题列表中看到他刚输入的主题。
我们在这个视图函数的末尾定义了变量context ,并使用稍后将创建的模板new_topic.html来渲染页面。这些代码不在if 代码块内,因此无论是用户刚进入new_topic 页面还是提交的表单数据无效,这些代码都将执行。用户提交的表单数据无效时,将显示一些默认的错误消息,帮助用户提供有效的数据。
下面来创建新模板new_topic.html,用于显示刚创建的表单:
new_topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
❶ <form action="{% url 'learning_logs:new_topic' %}" method='post'>
❷ {% csrf_token %}
❸ {{ form.as_p }}
❹ <button name="submit">Add topic</button>
</form>
{% endblock content %}
这个模板继承了base.html,因此其基本结构与项目“学习笔记”的其他页面相同。在❶处,定义了一个HTML表单。实参action 告诉服务器将提交的表单数据发送到哪里。这里将它发回给视图函数new_topic() 。实参method 让浏览器以POST请求的方式提交数据。
Django使用模板标签{% csrf_token %} (见❷)来防止攻击者利用表单来获得对服务器未经授权的访问(这种攻击称为跨站请求伪造 )。❸处显示表单,从中可知Django使得完成显示表单等任务有多简单:只需包含模板变量{{ form.as_p }} ,就可让Django自动创建显示表单所需的全部字段。修饰符as_p 让Django以段落格式渲染所有表单元素,这是一种整洁地显示表单的简单方式。
Django不会为表单创建提交按钮,因此我们在❹处定义了一个。
链接到页面new_topic
下面在页面topics 中添加到页面new_topic 的链接:
topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
--snip--
</ul>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic</a>
{% endblock content %}
这个链接放在既有主题列表的后面。