让用户能够输入数据
当前,只有超级用户能够通过管理网站输入数据,我们不想让用户与管理网站交互,因此我们将使用Django的表单创建工具来创建让用户能够输入数据的页面
Ⅰ、添加新主题
创建基于表单的页面的方法几乎与前面创建网页一样:定义一个URL,编写一个视图函数并编写一个模板,一个主要差别就是,需要导入包含表单的模块form.py
① 用与添加主题的表单:
在Django中,创建表单的最简单方式是使用ModelForm
,它根据我们在前面定义的模型中的信息自动创建表单。下面我们来创建一个名为form.py
的文件,将其存储到models.py
所在的目录中,并在其中编写你的第一个表单:
from django import forms
from .models import Topic
class TopicForm(forms.ModelsForm):
class Meta:
model = Topic
fields = ['text']
lables = ['text':'']
最简单的ModelForm
版本只包含一个内嵌的Meta类
,它告诉Django根据哪个模型创建表单,以及在表单中包含哪些字段;在最后一行代码中,它表示让Django不要为字段text
生成标签
② URL模式new_topic
当用户需要添加新主题时,我们将切换到网页http://localhost:8000/new_topic/
,下面是网页new_topic
的URL模式,我们将其添加到learning_logs/urls.py
中:
# --snip--
# urlpatterns = [
# --snip--
# 用于添加新主题的网页
url(r'^new_topic/$', views.new_topic, name='new_topic'),
]
③ 视图函数new_topics()
函数new_topic()
需要处理两种情形:1> 刚进入new_topic
网页(在这种情况下,它应显示一个空表单);2> 对提交的表单进行处理,并将用户重定向到网页topics,下面打开views.py
,执行以下代码:
# from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Topic
from .forms import TopicForm
# --snip--
def new_topic(request):
"""添加新主题"""
if request.method != ''POST:
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reserve('learning_logs:topics'))
context = {'form':form}
return render(request, 'learning_logs/new_topic.html', context)
我们导入了HttpResponseRedirect类
,用户提交主题后我们将使用这个类将用户重定向到网页topics;函数reverse()根据指定的URL模型确定URL,这意味着Django将在页面被请求时生成URL
④ GET请求和POST请求
创建Web应用程序
时,将用到的两种主要请求类型是GET请求
和POST请求
,对于只是从服务器读取数据的页面,使用GET请求;在用户需要通过表单提交信息时,通常使用POST请求,在处理所有表单时,我们都将指定使用POST方法。
代码的第16行表示要将提交的信息保存到数据库,必须先通过检查确定它们是有效的,函数is_valid()
核实用户填写了所有必不可少的字段(表单字段默认是必不可少的),且输入的数据与要求的字段类型一致。
⑤ 模板new_topic
下面来创建新模板new_topic.html
,用于显示我们刚创建的表单:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Add a new topic:</p>
<form>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">add topic</button>
</form>
{% endblock content%}
在代码的第6行Django使用模板标签来防止攻击者利用表单来获取对服务器未经授权的访问(这种攻击被成为跨站请求伪造),代码的第7行让我们知道:我们只需包含模板变量{{ form.as_p }}
就可让Django自动创建显示表单所需的全部字段,修饰符as_p
让Django以段落格式渲染所有表单元素,这是一种整洁地显示表单的简单方式。
⑥ 链接到页面new_topic
接下来我们在页面topics.html
中添加一个到页面new_topic
的链接:
# {% 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%}
这个链接放在了既有主题列表的后面,我们可以使用这个表单来添加一些新的主题。
Ⅱ、添加新条目
① 用于添加新条目的表单
我们需要创建一个与模型Entry
相关联的表单,但这个表单的定制程度要比TopicForm
要高一些,打开forms.py
并执行以下代码:
# from django import forms
from .models import Topic, Entry
# class TopicForm(forms.ModelForm):
# --snip--
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs) = {'cols': 80}}
在代码的第10行,我们定义了属性widgets
,小部件(widget
)是一个HTML表单元素,如单行文本框、多行文本区域或下拉列表,通过设置属性widget
,可覆盖Django选择的默认小部件,通过让Django使用forms.Textarea
,我们定制了字段‘text’的输入小部件,将文本区域的宽度设置为80列,而不是默认的40列,这给用户提供了足够的空间,可以编写有意义的条目。
② URL模式new_entry
打开learning_logs/urls.py
,执行以下代码:
# --snip--
# urlpatterns = [
# --snip--
# 用于添加新条目的页面
url(r'^new_entry/(?p<topic_id>\d+)/$', views.new_entry, name='new_entry'),
]
这个URL模式与形式http://localhost:8000/new_entry/id/
的URL匹配,其中id是一个与主题ID匹配的数字,代码(?p<topic_id>\d+)
捕获一个数字值,并将其存储在变量topic_id
中,请求的URL与这个模式匹配时,Django将请求和主题ID发送给函数new_entry()
③ 视图函数new_entry()
视图函数new_entry()
与函数new_topic()
很像,打开views.py
并执行以下代码:
# from django.shortcuts import render
# --snip--
# from .models import Topic
from .forms import TopicForm, EntryForm
# --snip--
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
if request.method != ''POST:
# 未提交数据:创建一个空表单
form = EntryForm()
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(reserve('learning_logs:topic', args=[topic_id]))
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
代码第20 21行在调用reverse()
时,需要提供两个实参:1> 要根据它来生成URL的URL模式的名称;2> 列表args
,其中包含要包含在URL中的所有实参。
④ 模板new_entry
模板new_entry
亦是类似于模板new_topic
,打开new_entry.html
并执行以下代码:
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topics' 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
接下来,我们需要在显示特定主题的页面中添加到页面new_entry
的链接,打开topic.html
,并执行以下代码:
# {% extends "learning_logs/base.html" %}
# {% block content %}
# <p>Topics</p>
# <p>Entries:</p>
<p>
<a href="{% url 'learning_logs:new_entry' topic_id %}">add new entry:</a>
</p>
# <ul>--snip--</ul>
# {% endblock content%}
现在用户可以添加新主题,还可以在每个主题中添加任意数量的条目,请在一些既有的主题中添加一些新条目,并尝试使用一下页面new_entry
Ⅲ、编辑条目
① URL模式edit_entry
这个页面的URL需要传递要编辑的条目的ID,打开learning_logs/urls.py,
执行以下代码:
# --snip--
# urlpatterns = [
# --snip--
# 用于编辑条目的页面
url(r'^edit_entry/(?p<entry_id>\d+)', views.edit_entry, name = 'edit_entry',)
]
② 视图函数edit_entry()
打开views.py
,并执行以下代码:
# from django.shortcuts import render
# --snip--
from .models import Topic, Entry
# from .forms import TopicForm, EntryForm
# --snip--
def edit_entry(request, entry_id):
"""编辑既有条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method != ''POST:
# 初次请求,使用当前条目填充表单
form = EntryForm(instance=entry)
else:
# POST提交的数据,对数据进行处理
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reserve('learning_logs:topic', args=[topic_id]))
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html', context)
③ 模板edit_entry
下面是模板edit_entry.html
,它与new_entry.html
相似:
{% extends "learning_logs/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topics' 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%}
④ 链接到页面edit_entry
现在,在显示特定主题的页面中,需要给每个条目添加到页面edit_entry
的链接,打开topic.html
并执行以下代码:
# --snip--
{% 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>
# --snip--
至此,“学习笔记”已经具备了需要的大部分功能,用户可添加主题和条目,还可根据需要查看任何一组条目,在下一次的分享中我们将实现一个用户注册系统,让任何人都能够向“学习笔记”申请账户,并创建自己的主题和条目。学习到这里,我不禁感叹Django的神奇魔力如此之强大,我想你也深深地感受到了,如果你一步一个脚印follow me的话,很快整个项目就快接近尾声了,虽然说这个东东说大不大说小不小,但马代码终究到底还是
经验问题,只有不断地去尝试去试错,你才会不断进步不断成功,过多的激励鼓励向上的话就不多说了,我只有个小小的愿望,那就是我们都不再是曾经的那个小白,那个新秀,那个新手,我们不只会‘Hello World’…
感谢您的阅读嗷💖💖💖