第三节:视图(Views)和模板(Templates)

时间:2022-08-29 23:23:39

目录

概览

视图是Django应用的网页的“类型”,一般服务于特定的功能并且有特定的模板,在我们的投票应用中,我们有下面四个视图:

  • Question  "index"页面——展示最新的几个问题。
  • Question  "detail"页面——显示问题内容,没有结果但是有一个投票表单。
  • Question  "results"页面——显示一个特定问题的结果
  • Vote "action"——处理在一个特定问题的进行具体的选择

在Django中,Web页面和其他内容是通过一个视图提供的,每一个视图由一个简单的Python函数表示(或者是类方法),Django将解析被请求的Url去选择一个视图(准确地说,是url域名后面的部分)。

从一个url到一个视图,Django使用所谓的‘Urlconfs’一个Urlconf映射Url模式到一个视图,本教程提供了Urlconfs使用的基本介绍,你也可以参考django.urls获得更多信息。

编写视图

polls/views.py添加视图:

def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id) def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id) def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)

polls.urls模块中添加url映射:

from django.conf.urls import url

from . import views

urlpatterns = [
# 例: /polls/
url(r'^$', views.index, name='index'),
# 例: /polls/5/
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# 例: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# 例: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

在浏览器打开“/polls/34”它将调用detail()方法并且显示你在url中提供的ID,同样的可以尝试打开“/polls/34/results”和“/polls/34/vote”。

当有人请求你网站的一个页面时,比如“/polls/34/”,Django将加载 mysite.urls Python模块因为它指定在ROOT_URLCONF配置中(mysite/settings.py)。它查找名为urlpatterns的变量并且按顺序遍历正则表达式。然后发现匹配"^polls/",它会替换掉匹配的文本("polls/")并将剩余的文本-"34/"交给"polls.urls"的url配置做进一步处理。它匹配r'^(?P<question_id>[0-9]+)/$',结果调用detail()视图:

detail(request=<HttpRequest object>, question_id='')

这个question_id='34'部分来自(?P<question_id>[0-9]+)。使用括号通过这个模式在一个“捕获”匹配的文本,并发送它给视图函数作为一个参数。?P<question_id>将被用做匹配模式的标识名称;[0-9]+匹配数字序列的正则表达式。

因为Url模式是正则表达式,所以格式没有任何限制,比如我们设置一个.html后缀的地址:

url(r'^polls/latest\.html$', views.index),

但是没必要这样做。

编辑视图实际做一些事情

每个视图负责两个事情之一,返回HttpResponse对象包含请求页面的内容,或者抛出异常例如Http404

你的视图可能从数据库读取记录,它可以使用一个模板系统例如Django的,-或者第三方Python模板系统。它可以产生一个PDF文件,输出XML,创建一个ZIP文件,任何你想要的,都可以使用Python库。

因为它的方便,让我们使用Django自己的数据库API,在第二部分教程中已经提到过了,在index()视图,我们显示最新的五条投票问题,以逗号分隔,按发布时间排序(polls/views.py):

from django.http import HttpResponse

from .models import Question

def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)

这儿有个问题,就是:页面的设计你硬编码到视图中的。如果你想要改变页面外观,你就要编辑python代码,让我们来使用Django的模板系统创建一个模板把设计从Python代码中分离出来。

首先在你的polls目录来创建一个名叫templates的文件夹,Django将在这个路径查找模板。

你的项目的TEMPLATES设置描述了Django将怎样加载和渲染模板,默认的配置文件配置了一个DjangoTemplates 后端其APP_DIRS选项设置为True。按照惯例DjangoTemplates 查找每一个INSTALLED_APPS应用的子目录“templates”。

在你刚刚创建的templates 目录下创建另一个名叫polls的文件夹,并且创建一个名叫index.html的文件,也就是说,你的模板应该放在 polls/templates/polls/index.html

注意:现在我们可能把我们的模板文件直接放在polls/templates(而不是创建另外一个polls子目录),但它实际上不是一个好主意。Django将选择第一个名称相匹配的模板,并且如果你已经有一个在不同应用名称相同的模板,Django是无法区分他们的,我们需要一个正确的指向项目模板并确保他们有简单的命名方式,也就是说通过将模板放置到templates的另一个目录中。

在模板中输入以下代码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中修改index视图去使用模板:

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

该代码加载名为polls/index.html的模板并传递context变量,context是一个字典映射在模板的变量名。

通过在你的浏览器加载页面“/polls/”,然后你应该可以看到Question的一个列表。

一个快捷方法:render()

它是一个加载模板非常常见的语法,添加一个context并返回呈现模板结果的

HttpResponse对象。Django提供一个快捷方法,现在我们来重写index()视图:

from django.shortcuts import render

from .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)

注意我们所有的视图都做到这一点的话,我们不在需要导入loaderHttpResponse

这个render()函数以请求对象作为第一个参数,第二个参数是模板名称和另外一个参数字典类作为可选参数。它返回一个指定上下文指定模板的HttpResponse对象。

抛出404错误

现在,让我们解决问题的详情视图 - 这个页面显示指定投票的问题文本,编辑视图polls/views.py:

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

这儿有个新概念:视图抛出Http404异常如果一个问题的ID不存在的话。

为了快速的展示一下上面的示例,在模板templates/polls/detail.html中输入简单的代码:

{{ question }}

一个快捷方法:get_object_or_404()

一个常用的语法去使用并且如果对象不存在抛出Http404异常。修改polls/views.py

from django.shortcuts import get_object_or_404, render

from .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})

get_object_or_404()包含一个Django模型参数和另外一个关键字参数,它传递到模型管理的get()函数,如果对象不存在抛出Http404

还有一个函数get_list_or_404(),工作原理和get_object_or_404()是一样的,使用filter()而不是get(),如果列表为空的话抛出404异常。

使用模板系统

回到我们投票应用的detail()视图。给一个question的context变量,编辑polls/detail.html模板:

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

模板系统使用点查找的语法去访问属性变量,例如{{ question.question_text }},

首先Django在一个字典查找question对象,如果属性查找失败,它将尝试列表索引查找。

方法调用发生在{% for %}循环:question.choice_set.all 将被解析为python代码question.choice_set.all(),它返回一个Choice迭代对象并且试用于{% for %}模板标签。

移除在模板中的硬编码网址

请记住,当我们在polls/index.html 模板编写一个链接时,这个链接是这样写的:

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

这种硬编码,紧密耦合的问题是,当我们的url需要变化时,将非常麻烦需要修改大量的模板。不过,既然你的polls.urls 中url()方法定义的有名称,那么你可以使用{% url %}模板标签:

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

这种方式是通过查找在polls.urls模块中定义的url来工作的,你可以准确的看到名为“detail”url定义如下:

...
# 做为{% url %}模板标签的“name”值
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

如果你想要修改投票的详细视图的url为其他的形式,也许像polls/specifics/12 ,你需要修改它在polls/urls.py

...
# 增加一个单词 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

Url名称的命名空间

本教程的项目仅仅有一个应用,polls。在实际项目中,可能有五个,十个或者更多应用。Django如何区分他们之间的Url名称?例如polls应用有一个detail视图,并且可能同一个项目有一个应用是blog也有一个detail视图。当使用{% url %} 模板标签时Django如何知道url是哪个应用视图的?

答案是在你的url配置中增加命名空间。在polls/urls.py文件中,增加一个app_name 去设置应用的命名空间

from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

现在修改你的polls/index.html 模板,从:

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

改成:

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

第三节:视图(Views)和模板(Templates)的更多相关文章

  1. 【Django笔记1】-视图&lpar;views&rpar;与模板&lpar;templates&rpar;

    视图(views)与模板(templates) 1,视图(views) ​ 将接收到的数据赋值给模板(渲染),再传递给浏览器.HTML代码可以直接放在views.py(文件名可任意更换),也可以放在t ...

  2. Django基础之视图&lpar;views&rpar;层、模板层

    目录 Django基础之视图(views)层.模板层 JsonResponse 向前端返回一个json格式字符串的两种方式 重写Django中的json的某个方法 form表单上传文件 FBV与CBV ...

  3. django在视图中使用模板

    在视图中使用模板   在学习了模板系统的基础之后,现在让我们使用相关知识来创建视图. 重新打开我们在前一章在 mysite.views 中创建的 current_datetime 视图. 以下是其内容 ...

  4. Django &lpar;六&rpar; 视图 views

    views 1. 视图及HttpRequest 和HttpResponse Django中的视图主要用来接受Web请求,并做出响应. 视图的本质就是一个Python中的函数 视图的响应分为两大类 1) ...

  5. django重点url,视图函数,模板语言

    django重点url,视图函数,模板语言url 1.django重点url无命名分组:re_path() 2.url第一个参:url未命别名分组就不需要views中参数一定,若命别名(?P<y ...

  6. (day52)四、视图层、模板层

    目录 一.视图层 (一)Request和Response对象 (1)Request对象 (2)Response对象 (二)JsonResponse对象 (1)前后端分离 (2)json_dumps_p ...

  7. Backbone&period;js 为复杂Javascript应用程序提供模型&lpar;models&rpar;、集合&lpar;collections&rpar;、视图&lpar;views&rpar;的结构

    Backbone.js 为复杂Javascript应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和 自定义事件:集合附有可枚举函数 ...

  8. jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs

    如何分组管理权限,如何实现不同用户组显示对应视图views中不同的jobs,建议使用Role Strategy Plugin插件. 1.安装Role Strategy Plugin插件. 2.“系统管 ...

  9. Django学习总结之模板templates

    - django模板: templates - 模板分为两个过程: 1, 加载 : loader.get_template('xxx.html') 返回值是一个template对象 2, 渲染 : t ...

  10. 用 php 实现一个视图组件和模板引擎——基础

    只要不是做后端接口开发和一些作为守护进程之类的服务器脚本,大多数时候都是在和浏览器打交道,因此合理组织并展现 html 标签是最为常见的工作.一般大家使用框架时,都会自带有一套视图组件和模板引擎. 我 ...

随机推荐

  1. java-关于浏览器的判断

    一.判断是手机还是电脑浏览器 public final static String[] agent = { "Android", "iPhone", &quot ...

  2. ASP&period;NET MVC删除数据

    Index.cshtml @model IEnumerable<MvcExample.Models.Category> <script type="text/javascr ...

  3. 804 pretest 解题

    Answers with Explanations 1. c) s1 and s2 not equal s1 and s3 equal JVM sets a constant pool in whic ...

  4. xcode快捷键的使用

    1.统计Xcode项目代码行数 1   打开终端. 2  用ls和cd进到你项目的路径. 3   输入下面的指令: grep -r "\n" classes | wc -l (cl ...

  5. NET中级课--文件&comma;流&comma;序列化1

    1.对于机器的角度来看,任何文件都是二进制的0和1. 2.   位:bit,一个1或0就是1位. 字节:byte,每8位一个字节.一个字节的范围就是00000000到1111111,换成10进制就是0 ...

  6. scull&lowbar;p&lowbar;read&lpar;&rpar;函数分析

    /* * Data management: read and write */ static ssize_t scull_p_read (struct file *filp, char __user ...

  7. tomcat配置https协议

    tomcat配置https协议 1.找到本地jdk底下的bin目录,bin目录底下存在文件keytool.exe(在bin目录下空白处,按住shift右击,打开命令窗口,如下图) 2.在cmd的命令窗 ...

  8. STL--sort源码分析

    SGI STL sort源码 temlate <class RandowAccessIterator> inline void sort(RandowAccessIterator firs ...

  9. 【svn】本地文件夹同步到SVN

    本地代码上传至SVN 起因: 我在开发项目代码时往往在本地开发很久,在基本功能完成时才上传svn,添加版本控制. 做法: 右键 TortoiseSVN - Repo browser 在希望项目存储的根 ...

  10. C语言---指针变量详解3

    指针可以指向一份普通类型的数据,例如 int.double.char 等,也可以指向一份指针类型的数据,例如 int *.double *.char * 等.如果一个指针指向的是另外一个指针,我们就称 ...