文章目录
往期回顾:
Web 应用程序的核心是让用户都能够注册账户并能够使用它。
1. 让用户能够输入数据
在建立用于创建用户账户的身份验证系统之前,我们先来添加几个页面,
让用户能够输入数据。
添加新的主题
首先,让用户能够添加新的主题。
创建基于表单的页面的方法几乎与前面创建网页一样:定义一个URL,
编写一个视图函数并编写一个模板。 //这里需要导入包含表单的模块 forms.py
用于添加主题的表单
这里,我们将可以让用户输入并提交信息的页面称为表单,哪怕它看起来不像表单。
用户输入信息时,需对其进行校验,确认提供的信息是并非恶意的,且是正确的数据类型。然后在对这些信息有效信息进行处理,将其保存到数据库的合适地方。这些工作皆由 Django 自动完成。
在Django中,创建表单的最简单方式是使用 ModeForm,它根据模型自动创建表单。
#创建名为 forms.py的文件,将其存储在 models.py 的同级目录
# 导入forms模块
from django import forms
# 导入Topic模型
from .models import Topic
# 定义TopicForm类,该类继承于forms.ModelForm
class TopicForm(forms.ModelForm):
# 嵌套Meta类,告诉Django根据哪个模型创建表单
class Meta:
# 告诉Django表单中该含有的字段
model = Topic
fields = ['text']
labels = {'text' : ''}
URL 模式new_topic
这个新网页的URL简单且具有描述性,当用户需要添加新的主题时,我们切换到
http://localhost:8000/new_topic/
# learning_logs/urls.py
# 用于添加新主题的网页
url(r'^new_topic/$',views.new_topic, name='new_topic'),
编写视图函数 new_topic()
函数 new_topic() 需要处理两种情形:
刚进入网页new_topic网页(该情况下应该显示一个表单);
对提交的表单数据进行处理,并将用户重定向到网页 topics;
# views.py
from django.http import HttpResponseRedirect
from django.urls import reverse
from .forms import TopicForm
# new_topic 函数解析:
> 函数 new_topic()将请求对象作为参数。用户初次请求该网页时,其浏览器将发送GET请求;用户填写并提交表单时,其浏览器将发送POST请求。根据请求的类型,我们可以确定用户请求的是空表单(GET请求)还是要求填写好的表单进行处理(POST请求)
def new_topic(request):
# 添加新主题
> 确定请求方式为GET还是POST,如果请求方法不是POST,请求的可能是GET,因此需要返回一个空表单(即便请求的是其他方式,但返回一个空表单是没有问题的。)
if request.method != 'POST':
# 未提交数据:创建一个新表单
> 创建一个TopicForm 实例,将其存储在变量form中,通过上下文字典将这个表单发送给模板。由于实例TopicForm实例化时没有指定参数,Django将创建一个可供用户填写的空表单。
form = TopicForm()
> 如果请求方式为POST,将执行else代码段。对提交的表单数据进行处理。我们使用用户输入的数据(它们存储在request.POST中)创建一个TopicForm实例。这样对象form将包含用户提交的信息。
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
> 函数 is_valib用于校验用户提供的信息是否有效
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
GET请求和POST请求
创建Web应用程序时,会用到两种主要请求类型:GET 和 POST。对于只从服务器读取数据使用 GET请求。在用户需要提交数据时,通常使用 POST请求。此项目中我们处理所有表单数据都使用 POST请求。
模板new_topic
创建new_topic.html 模板,用于显示刚才创建的表单:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Add a topic:</p>
<form action="{% url 'learning_logs:new_topic' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">add topic</button>
</form>
{% endblock content%}
链接到页面 new_topic
在页面topics中添加一个到页面new_topic 的链接
topics.html:
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
效果测试:
添加成功了!nice
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
添加新条目
现在用户可以添加新的主题了。但他们还想添加新条目。我们再定义URL,
编写视图函数和模板,并链接到添加新条目的网页。但再次之前,
在forms.py 中再添加一个类:
# forms.py
form .models import Topic,Entry
class EntryForm(forms.ModelForm):
# Meta 类指出了表单基于的模型及表单中涵盖数据
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
URL模式 new_entry
在用于添加新条目页面的URL模式中,需要包含实参 topic_id,因为条目必须与指定的主题相
关联,在 learning_logs/urls.py中添加:
# 用于添加新条目的页面
url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
视图函数 new_entry()
# views.py
> import 语句包含了刚创建的EntryForm
from .forms import TopicForm, EntryForm
> new_entry包含形参 topic_id。用于存储从URL中获得的值,通过topic_id获取正确的主题
def new_entry(request,topic_id):
# 在特定的主题中添加条目
topic = Topic.objects.get(id=topic_id)
# > 检查校验方式,GET执行if
if request.method != 'POST':
# 未提交的数据,创建一个空表单
form = EntryForm()
# > POST 执行else
else:
# POST提交的数据,创建一个空表单
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return HttpResponseRedirect(reverse('learning_logs:topic',args=[topic_id]))
context = {'topic': topic,'form': form}
return render(request, 'learning_logs/new_entry.html',context)
模板 new_entry
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>Add a new entry:</p>
<form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name='submit'>add entry</button>
</form>
{% endblock content %}
链接到页面 new_entry
topic.html
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<p>
<a href="{% url 'learning_logs:new_entry' topic.id %}">Add a new Entry:</a>
</p>
<ul>
{% for entry in entrys %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
</li>
{% empty %}
<li>
Three are no entries for this topic yet.
</li>
{% endfor %}
</ul>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
{% endblock content %}
效果图:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
编辑条目
下面创建一个页面,我们让用户能够自己编辑既有的条目
URL模式edit_entry
urls.py
这个页面的URL需要传递要编辑的条目的ID
# 修改后的 learning_logs/urls.py 如下:
# 用于编辑条目的页面
re_path(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry, name='edit_entry'),
视图函数
页面 edit_entry 收到GET请求时,edit_entry() 将返回一个表单,让用户能够对条目
进行编辑。该页面收到POST请求时,它将修改后的文本保存到数据库中
# 编辑既有条目
def edit_entry(request,entry_id):
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method != 'POST':
form = EntryForm()
else:
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topic',args=[topic.id]))
content = {'entry':entry, 'topic':topic, 'form': form}
return render(request,'learning_logs/edit_entry.html', content)
模板 edit_entry
{% extends "learning_logs/base.html" %}
{% block content %}
<P><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></P>
<P>Edit entry:</P>
<form action="{% url 'learning_logs:edit_entry' entry.id %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">save changes</button>
</form>
{% endblock content %}
链接到页面 topic
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
<p>
<a href="{% url 'learning_logs:edit_entry' entry.id %}">edit entry</a>
</p>
</li>
{% empty %}
<li>
There are no entries for this topic yet.
</li>
{% endfor %}