前面两个部分我们介绍了投票应用的框架和后台管理部分。接下来舍得要介绍这个应用面向用户的界面。

这里我们要引入一个新的概念,“视图”。在Django中,视图是一根连接模型和模板的纽带,它决定哪些数据要呈现给用户。

来看一下Django的这几个核心概念:

  • 模型:负责和数据库打交道,把数据传入、传出给数据库;
  • 模板:负责最终显示给用户的页面的显示方式;
  • 视图:将模型和模板连接在一起,它决定了哪些数据要显示给用户;
  • 链接:Django中有一项url配置,它充当着整个程序的入口,用户在地址栏中输入地址时,由链接模块去决定将这个地址分发到哪里;

带着这些概念,我们来写下本例中的第一个视图:

 

14.编写视图


编辑polls/views.py 文件,添加下面的内容:

polls/views.py

from django.http import HttpResponse

def index(request):
return HttpResponse("嗨,哥们,你现在正在访问的是投票应用的首页.")

这可能是Django中最简单的视图了。要想让视图的内容最终呈现给用户,我们还需要将这个视图关联(术语叫映射)到URL文件中。

现在我们需要在polls文件夹下创建一个叫url.py的文件,创建完后,你的应用文件夹应该是下面这个样子:

polls/
__init__.py
admin.py
models.py
tests.py
urls.py
views.py

编辑polls/urls.py 文件,加入下面这些代码:

polls/urls.py

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
)

此时,从应用到用户那条路还没打通,我们还需要在站点的urls.py中把链接指向刚编辑完的urls.py。

编辑mysite/urls.py 文件,让它变成下面这样:

mysite/urls.py

from django.conf.urls import patterns, include, url
from django.contrib import admin urlpatterns = patterns('',
url(r'^polls/', include('polls.urls')),
url(r'^admin/', include(admin.site.urls)),
)

注意观察第四行,它把我们的polls/urls.py关联到了mysite/urls.py 中。

url()中的第一个参数,如”r'^polls/'”,这个叫正则表达式。关于正则表达式的内容,童鞋们可以参阅一些相关的书籍或文章,比如《精通正则表达式》或舍得写的正则表达式实战教程。

上面这个操作做完后,我们打开浏览器,在地址栏中输入:

可以看到我们的工作成果:

我们再来添加一些视图,编辑polls/views.py 文件,添加下面的内容:

polls/views.py

def detail(request, question_id):
return HttpResponse("你正在查看的是问题%s." % question_id) def results(request, question_id):
response = "你正在查看的是问题%s的投票结果."
return HttpResponse(response % question_id) def vote(request, question_id):
return HttpResponse("你正在为问题%s投票." % question_id)

现在我们只需要编辑polls/urls.py 文件就可以让视图生效了:

polls/urls.py

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
# 如: /polls/
url(r'^$', views.index, name='index'),
# 如: /polls/5/
url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
# 如: /polls/5/results/
url(r'^(?P<question_id>\d+)/results/$', views.results, name='results'),
# 如: /polls/5/vote/
url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
)

转到浏览器界面,分别用下面这些链接去访问一下:

http://127.0.0.1:8000/polls/1/
http://127.0.0.1:8000/polls/1/result
http://127.0.0.1:8000/polls/1/vote

我们来分析一下Django的处理流程。在本例中,当用户访问到http://127.0.0.1:8000/polls/1/results这样的链接时:

  • Django会先在mysite/urls.py 中找“^poll/”;
  • 找到后,Django会去掉“poll/”,把剩下的“1/results”发到polls/urls.py 中继续处理;
  • 在polls/urls.py 发现能匹配到“r'^(?P<question_id>\d+)/results/$'”,最终显示polls/views.py中的results视图;

15.进阶版视图


前面的视图仅仅是让大家熟悉Django的基本处理流程。现在,我们来进入实战状态,编写真正有用的视图。

编辑polls/views.py 文件,让它变成下面这样:

polls/views.py

from django.http import HttpResponse

from polls.models import Question

def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([p.question_text for p in latest_question_list])
return HttpResponse(output) # 下面的那些视图暂时留着别删 (detail, results, vote)

看下效果:

数据库里的内容显示出来了。

但这种做法并不可取。因为我们把控制页面显示效果的编码放在.py文件中,这样的方式我们称之为”硬编码“,它意味着以后每一次要改动页面效果,都需要修改这个.py文件,显然极为不便。

正确的做法是,把页面显示相关的部分交给模板系统来处理。

首先,请在polls文件夹下建立templates文件夹,Django会自动搜索到它。

在templates文件夹中建立一个文件夹,叫polls,然后在这个polls文件夹下新建一个index.html文件,这是我们的投票应用的首页模板。这个模板的路径应该是:

polls/templates/polls/index.html

把下面这些代码添加到index.html中(Html文件用文本编辑器来完成就可以了,舍得推荐使用emeditor):

polls/templates/polls/index.html

{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

模板做好了,我们来修改一下视图,编辑polls/views.py 文件,改成这样:

polls/views.py

from django.http import HttpResponse
from django.template import RequestContext, loader from polls.models import Question def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = RequestContext(request, {
'latest_question_list': latest_question_list,
})
return HttpResponse(template.render(context))

在上面这段代码中,我们先载入“polls/index.html”这个模板,传递给它一个叫context的对象,这个context包含了我们想要显示的数据。

来看下效果:

“What's Up?”变成了链接的形式,链接指向了投票的内容页。

上面这样的写法,在Django中有更便捷的方式,我们来修改polls/views.py 文件:

polls/views.py

from django.shortcuts import render

from polls.models import Question

def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)

这样的代码更加简洁。而且更易于阅读。

render()函数使用request作为第一个参数,模板名作为第二个参数,把context这个字典类型数据作为第三个参数。它会用数据用模板渲染好,呈现到用户面前。

16.处理404错误


现在,让我们来着手设计投票内容页。

编辑polls/views.py 文件:

polls/views.py

from django.http import Http404
from django.shortcuts import render from polls.models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404
return render(request, 'polls/detail.html', {'question': question})

这里引入了一个新的概念,当用户访问的投票项不存在时,视图会抛出一个Http404异常来通知用户。

给上面这个视图配上对应的模板,建立detail.html文件 ,并添加以下内容:

polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

刚才那个视图,Django里有更为便捷的写法,编辑polls/views.py 文件,把它改成这样:

polls/views.py

from django.shortcuts import get_object_or_404, render

from polls.models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})

现在,点击刚才浏览器中的那个“What's Up?”链接,我们就可以看到象下面这样的页面:

在Django的模板系统中,我们要注意的是两类符号,一类是双大括号,如:{{question.question_text }};另一类是{% 的形式,如{% for choice in question.choice_set.all %}。前者仅仅是一个值,后者则相当于一段程序。

在本例中,{% for %} 代表了一个for循环,question.choice_set.all包含了这个投票的所有选项,用一个for循环就可以把它全部显示出来。

17.移除模板中的硬编码


在我们刚才的模板中,也存在着我们前面说过的硬编码问题。

像下面这样的代码:

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

这里的”/polls/{{ question.id }}/“采用常量的方式写入链接,一旦以后有变动,要修改链接,可能会产生大量的额外工作量。

好在我们可以解决这个问题。上面的这段代码我们可以写为:

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

当此模板被呈现的时候,Django会自动到你定义的urls.py文件中去寻找”detail”这个名称,它会在polls/urls.py中找到:

...
# 这里的'name'值就是{% url %} 模板标签调用的地方。
url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
...

这样,你要修改链接,比如把它改0“成polls/specifics/12/”,不用去逐个修改模板,只要改动polls/urls.py就可以了,如:

...
# 链接中加入'specifics'
url(r'^specifics/(?P<question_id>\d+)/$', views.detail, name='detail'),
...

18.创建URL命名空间


我们这个例子只有一个应用,而在真实的项目中,往往五个、十个、二十个甚至更多的应用。在这种时候,url名称会不会被搞混掉?举个例子,我们这个polls应用有个叫detail的视图,某一天,在同一项目下增加了一个blog的应用,它也有一个detail视图,怎么来区分呢?

这就是命名空间存在的意义。

编辑mysite/urls.py文件,增加命名空间的属性:

mysite/urls.py:

from django.conf.urls import patterns, include, url
from django.contrib import admin urlpatterns = patterns('',
url(r'^polls/', include('polls.urls', namespace="polls")),
url(r'^admin/', include(admin.site.urls)),
)

修改模板文件polls/index.html,把它从:

polls/templates/polls/index.html

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

改为:

polls/templates/polls/index.html

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

这样,以后即便应用再多,也不会起冲突了。

 

【未完待续】

本文版权归舍得学苑所有,欢迎转载,转载请注明作者和出处。谢谢!

作者:舍得

首发:舍得学苑@博客园

实战Django:官方实例Part3的更多相关文章

  1. 实战Django:官方实例Part1

    [写在前面] 撰写这个实战系列的Django文章,是很久之前就有的想法,问题是手头实例太少,一旦开讲,恐有"无米下锅"之忧. 随着对Django学习的深入,渐渐有了些心得,把这些心 ...

  2. 实战Django:官方实例Part2

    我们接着Part1部分往下讲.我们在part1中启动服务器后,并没有在管理页面中发现新添加的Polls应用,怎么办捏? 7.在管理界面中显示Question 只要注册一下这个应用就可以了.编辑poll ...

  3. 实战Django:官方实例Part6

    我们终于迎来了官方实例的最后一个Part.在这一节中,舍得要向大家介绍Django的静态文件管理. 现在,我们要往这个投票应用里面添加一个CSS样式表和一张图片. 一个完整的网页文件,除了html文档 ...

  4. 微软官方实例 RazorPagesMovie 在 asp.net core 2.1 版本下的实战

    微软官方实例 RazorPagesMovie 在 asp.net core 2.1 版本下的实战 友情提示: 操作系统: MacOS 10.13.5 dotnet core: version 2.1. ...

  5. 实战Django:简易博客Part1

    舍得学习新技能的时候,通常不喜欢傻读书--捧着一本阐述该项技能的书籍,然后傻看,一路看下来,脑子里塞满了新的概念.知识点,头是越来越大,但技能却几乎没掌握半分. 多年来,舍得养成了用做实例来学习新技能 ...

  6. 对《[Unity官方实例教程 秘密行动] Unity官方教程《秘密行动》(十二) 角色移动》的一些笔记和个人补充,解决角色在地形上移动时穿透问题。

    这里素材全是网上找的. 教程看这里: [Unity官方实例教程 秘密行动] Unity官方教程<秘密行动>(九) 角色初始设定 一.模型设置: 1.首先设置模型的动作无限循环. 不设置的话 ...

  7. Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)

    相关资料:1.http://blog.csdn.net/laorenshen/article/details/411498032.http://www.cnblogs.com/findumars/p/ ...

  8. 微信应用号开发知识贮备之altjs官方实例初探

    天地会珠海分舵注:随着微信应用号的呼之欲出,相信新一轮的APP变革即将发生.从获得微信应用号邀请的业内人士发出来的一张开发工具源码截图可以看到,reacjs及其相应的FLUX框架altjs很有可能会成 ...

  9. 源于《Unity官方实例教程 “Space Shooter”》思路分析及相应扩展

    教程来源于:Unity官方实例教程 Space Shooter(一)-(五)       http://www.jianshu.com/p/8cc3a2109d3b 一.经验总结 教程中步骤清晰,并且 ...

随机推荐

  1. Android——ImageSwitcher 图片切换

    public class ImageSwitcherActivity extends Activity implements OnClickListener,        ViewFactory { ...

  2. Vertex中实现每顶点光照的镜面高光效果

    1,基础知识讲解 一个物体在自然界会收到三种光的影响,周围的环境光.漫反射和镜面反射.那么对于计算机要想模拟现实中的光照,就应该也会实现这三种基本光照->环境光.漫反射.镜面高光.对于这三种光照 ...

  3. while((c = getchar()) != EOF)(键盘输入问题)

    问题描述: 样例输入:O S 样例输出:I A 代码实现: #include <stdio.h> char *s = "`1234567890-=qwertyuiop[]\\as ...

  4. Sql语句直接返回XML文件

    通过Sql语句直接返回XML文件 select UserID,UserName,AccountName,LoginPassword from users for xml raw('Users') ,r ...

  5. Solarwinds Orion NPM实战视频演示

    Orion Network Performance Monitor是全面的带宽性能监控和故障管理软件,能监控并收集来自路由器.交换机.服务器和其他SNMP设备中的数据,您可以直接从Web浏览器上观察您 ...

  6. 用C++实现网络编程---抓取网络数据包的实现方法

    一般都熟悉sniffer这个工具,它可以捕捉流经本地网卡的所有数据包.抓取网络数据包进行分析有很多用处,如分析网络是否有网络病毒等异常数据,通信协议的分析(数据链路层协议.IP.UDP.TCP.甚至各 ...

  7. linux网卡绑定

  8. flask-admin

    初始化 class Admin(app=None, name=None, url=None, subdomain=None, index_view=None, translations_path=No ...

  9. Memento

    #include <iostream> #include <string> using namespace std; class Memento { public: Memen ...

  10. node中的流程控制中,co,thunkify为什么return callback()可以做到流程控制?

    前言 我在学习generator ,yield ,co,thunkify的时候,有许多费解的地方,经过了许多的实践,也慢慢学会用,慢慢的理解,前一阵子有个其他项目的同事过来我们项目组学习node,发现 ...