- 读书笔记 | Python学习之旅 Day2
- 【day 8】python编程:从入门到实践学习笔记-文件和异常
- 【day 7】python编程:从入门到实践学习笔记-类(末附练
- 【day 5】python编程:从入门到实践学习笔记-用户输入和
- 【day 9】python编程:从入门到实践学习笔记-测试代码(
- 【day 10】python编程:从入门到实践学习笔记-基于Dj
- 【day 2】python编程:从入门到实践学习笔记-列表以及其
- 【day 4】python编程:从入门到实践学习笔记-字典(末附
- 【day 6】python编程:从入门到实践学习笔记-函数(末附
- 【day 3】python编程:从入门到实践学习笔记-if 语句
学习笔记目录
【day 1】python编程:从入门到实践学习笔记-安装、变量和简单数据类型
【day 2】python编程:从入门到实践学习笔记-列表以及其操作
【day 3】python编程:从入门到实践学习笔记-if 语句(末附练习答案代码)
【day 4】python编程:从入门到实践学习笔记-字典(末附练习答案代码)
【day 5】python编程:从入门到实践学习笔记-用户输入和while循环(末附答案代码)
【day 6】python编程:从入门到实践学习笔记-函数(末附练习答案代码)
【day 7】python编程:从入门到实践学习笔记-类(末附练习答案代码)
【day 8】python编程:从入门到实践学习笔记-文件和异常(末附练习答案代码)
【day 9】python编程:从入门到实践学习笔记-测试代码(末附练习答案代码)
【day 10】python编程:从入门到实践学习笔记-Django入门(一)
【day 11】python编程:从入门到实践学习笔记-Django入门(二)
【day 12】python编程:从入门到实践学习笔记-Django入门(三)
【day 13】python编程:从入门到实践学习笔记-Django入门(四)
【day 14】python编程:从入门到实践学习笔记-用户账户(一)
【day 15】python编程:从入门到实践学习笔记-用户账户(二)
【day 16】python编程:从入门到实践学习笔记-用户账户(三)
【day 17】python编程:从入门到实践学习笔记-设计样式和部署(一)
【day 18】python编程:从入门到实践学习笔记-设计样式和部署(二)& 补充
第十九章 用户账户(一)
让用户能够输入数据(表单)
在创建用户账户身份验证系统之前,先添加几个页面,让用户能偶输入数据。添加新主题、添加新条目以及编辑既有条目。
添加新主题
1.用于添加主题的表单
创建一个forms.py文件与models.py放在同一目录下。
from django import forms
from .models import Topic
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
TopicForm类继承了forms.ModelForm,其包含一个内嵌的Meta类。Meta类指定了根据哪个模型创建表单,以及在表单中包含哪些字段。
在这里,我们根据模型Topic创建了一个表单,该表单只包含字段text,且不用为字段text生成标签。
2.URL模式new_topic
# learning_logs/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^topics/$', views.topics, name='topics'),
url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
url(r'^new_topic/$', views.new_topic, name='new_topic'),
]
3.视图函数new_topic()
# learning_logs/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(reverse('learning_logs:topics'))
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
用户提交主题后使用HttpResponseRedirect类将用户重定向到网页topics。函数reverse()
根据指定的URL模式确定URL,即django将在页面被请求时生成URL。
4.GET请求和POST请求
GET请求:从服务器读取数据;
POST请求:通过表单提交信息。
在上述代码的else部分中,我们将使用-存储在request.POST的用户输入数据-创建一个TopicForm实例并赋值给对象form。
将提交的信息保存到数据库之前,得检查其是否有效。函数is_valid()
核实用户填写了所有必不可少的字段,且输入的数据与要求的字段类型一致。如果所有字段有效,调用函数save()
将表单数据写入数据库。
最后使用函数reverse()
获取页面topics的URL,并将其传递给HttpResponseRedirect()
,后者将用户浏览器重定向到页面topics查看用户刚输入的主题。
5.模版new_topic
<!-- new_topic.html -->
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Add a new 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 %}
定义表单使的实参action指定了服务器将提交的表单数据发送的目的地。在这里我们将它发回给视图函数new_topic()
。实参method
让浏览器以POST请求的方式提交数据。
模板标签{% csrf_token %}防止攻击者利用表单来获得对服务器未经授权的访问(跨站请求伪造)。
模板变量{{ form.as_p }}让django自动创建显示表单所需的全部字段。修饰符as_p表示以段落格式渲染所有表单元素。
6.链接到页面new_topic
在页面 topics中添加一个到页面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 %}
运行服务器可以看到
![](https://img.haomeiwen.com/i9578471/26e819805e8eefb2.png)
![](https://img.haomeiwen.com/i9578471/5aa42c73d5191585.png)
添加新条目
1.用于添加新条目放入表单
定制一个与模型Entry相关联的表单
from django import forms
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
同样导入Entry,新类继承forms.ModelForm,新类包含的Meta类指出表单基于的模型以及表单中包含的字段。
在Meta类中我们定义了属性widgets。小部件(widget)是一个HTML表单元素,比如单行文本框、多行文本区域或者下拉列表。通过设置这个属性覆盖django默认的小部件,并把文本区域的宽度设置为80列,而不是默认的40列。
2.URL模式new_entry
修改urls.py
#learning_logs/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
#--snip--
url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
]
这个URL模式与形式为http://127.0.0.1:8000/new_entry/id/
的URL匹配,其中id是一个与主题id匹配的数字。(?P<topic_id>\d+)
捕获一个数值存储在变量topic_id中。模式匹配时django把请求和主题id发给函数new_entry()
。
3.视图函数new_topic
修改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, 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(reverse('learning_logs:topic',args=[topic_id]))
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
new_entry = form.save(commit=False)
表示创建一个新的条目对象并把它存储到new_entry中,但是不保存到数据库。接着把new_entry的topic设置为此函数开头从数据库中获取的主题,然后调用save()
保存到数据库,这样才能确保与正确的主题相关联。
在调用reserve()
时需要提供两个实参。第一个是根据它来生成URL的URL模式的名称。第二个是列表args,其中存储着要包含在URL中的所有实参。
4.模板new_entry
类似new_topic.html
#new_entry.html
{% 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 %}
表单的实参action包含URL中的topic_id值,让视图函数能够把新条目关联到正确的主题。
5.链接到页面new_entry
在显示特定主题的页面中添加到页面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 new entry</a>
</p>
<ul>
#--snip--
</ul>
{% endblock content %}
运行服务器可以看到
![](https://img.haomeiwen.com/i9578471/5f0670e432dc5b65.png)
编辑条目
1.URL模式edit_entry
此页面的URL需要传递要编辑的条目的ID。
#learning_logs/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
#--snip--
url(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry,name='edit_entry'),
]
在URLhttp://127.0.0.1:8000/edit_entry/id/
中传递的id存储在形参entry_id中。模式匹配时把请求发送给视图函数edit_entry()
。
2.视图函数edit_entry
页面edit_entry收到GET请求时,edit_entry()
返回一个表单,让用户对条目进行编辑。该页面收到POST请求(条目文本经过修订)时,把修改后的文本保存到数据库中。
修改views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
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(reverse('learning_logs:topic',args=[topic.id]))
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html', context)
首先获取需要修改的条目对象以及该条目相关联的主题。当请求方法为GET时执行if代码块,实参instance=entry表示使用既有条目对象中的信息填充创建的表单。
处理POST请求时,传递实参instance=entry和data=request.POST让django根据既有条目对象创建表单实例并根据request.POST中的相关数据对其进行修改。
3.模板edit_entry
类似new_entry.html
#edit_entry.html
{% 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 %}
在标签{% url %}
中将条目id作为实参。
5.链接到页面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--
运行服务器可以看到
![](https://img.haomeiwen.com/i9578471/0587f946b21c1023.png)
网友评论