概述

Django中的特方法,该方法代表了Django的Web页面,并且视图具有特定的模板。以博客应用为例进行说明,在博客应用中应该包含下面的视图:

  • 博客主页:显示最近的一些记录;
  • 详细页面:单个详细页面的入口;
  • 年/月/日:存档页面,显示记录的所有年/月/日;
  • 评论动作:分发评论请求到对应入口;

在poll应用中,我们将会创建如下视图:

  • Question "index"页面:显示最近的questions;
  • Question "detail"页面:显示问题内容,没有结果的投票表单;
  • Question "results"页面:显示具体question的结果;
  • Vote action:处理具体问题的投票选择;

在Django中,Web页面或者其他内容都有视图来交付处理,Django通过检查请求的URL来选择对应的视图。关于URL分发处理部分参考URL分发器,或者继续阅读后续博客。

编写更加丰富的视图

在我们的polls/view.py文件中添加几个视图,这几个视图跟我们之前的视图函数稍微有点儿区别,因为他们带有一个参数,其代码如下所示:

  1. def detail(request, question_id):
  2. return HttpResponse("You're looking at question %s." % question_id)
  3. def results(request, question_id):
  4. response = "You're looking at the result of question %s."
  5. return HttpResponse(response % question_id)
  6. def vote(request, question_id):
  7. return HttpResponse("You're voting on question %s." % question_id)

接下来,需要把这些新的视图添加到poll.urls模块中去,添加的方式就是通过调用path()函数,代码如下:

  1. from django.urls import path
  2. from . import views
  3. urlpatterns = [
  4. path('', views.index, name='index'),
  5. path('<int:question_id>/', views.detail, name='detail'),
  6. path('<int:question_id/results/>', views.results, name='results'),
  7. path('<int:question_id/vote/>', views.vote, name='vote'),
  8. ]

在浏览器中进行测试:

  • /polls/34:返回detail()方法对应的内容,其ID是在URL里面提供的;
  • /polls/34/results:显示results页面内容;
  • /polls/34/vote:显示vote页面内容;

当我们需要访问某个页面时,我们在浏览器里面输入"/polls/34"Django是如何寻找到对应视图并显示出来的呢?下面对这个问题做以回答:

  • 首先,Django会根据settings.py文件的ROOT_URLCONF配置项取加载mystie.urls模块;
  • 其次,在mysite.urls模块中顺序遍历urlpatterns变量;
  • 再次,当匹配到"polls/"时,剥离掉匹配的内容"polls/",携带剩余待匹配内容"34/"进入到"polls.urls"模块,继续进行处理;
  • 最后,遍历polls.urls的patterns变量,匹配到"int:question_id/"进而调用detail()视图函数,其结果像下面:
  1. detail(request=<HttpRequest object>, question_id=34)

上面都是对视图函数的简单操作,接下来我们会学习些实际的东西。

每个视图函数都只做1-2件事情:返回包含请求页面内容的HttpResponse对象,或者抛出Http404异常;视图函数可以读取数据库的记录;可以使用Django自带的模板系统,或者其他第三方Python模板系统;它可以生成PDF,导出XML,创建ZIP文件等,使用Python库函数可以实现一切你想实现的。

由于它非常的方便,我们就使用Django自带的数据库API来进行演示,在polls/views.py文件添加如下代码:

  1. from django.http import HttpResponse
  2. from .models import Question
  3. def index(request):
  4. latest_question_list = Question.objects.order_by('-pub_date')[:5]
  5. output = ', '.join([q.question_text for q in latest_question_list])
  6. return HttpResponse(output)
  7. # 保持其他视图函数不变

这里有个问题:Web页面是通过视图函数硬编码方式来设计的。如果我们想更改页面,我们必须修改这里的Python代码,这样做非常的不友好。因此,我们将使用Django的模板系统,来分离页面的设计和Python代码的耦合,取而代之的是让视图函数去使用模板。

在polls目录下面创建一个目录:templates,Django会自动到该目录里面查找模板文件。其查找机制是:在项目的配置文件settings.py中,"TEMPLATES"定义了Django如何加载和渲染模板;默认配置了一个APP_DIRS为TRUE的DjangoTemplates后台,按照惯例DjangoTemplates会在每个INSTALLED_APPS中查找"templates"这个子目录。

接下来,在templates目录里面创建空目录:polls,在该空目录里面创建一个index.html文件。换句话说,我们的模板目录应该是polls/templates/polls/index.html

在刚才创建的模板文件中,写入下面代码:

  1. {% if latest_question_list %}
  2. <ul>
  3. {% for question in latest_question_list %}
  4. <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
  5. {% endfor %}
  6. </ul>
  7. {% else %}
  8. <p>No polls are available.</p>
  9. {% endif %}

现在,使用模板更新我们之前的index视图函数polls/views.py,代码如下:

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

上述代码会加载模板polls/index.html,并且将该模板传递给上下文环境,该上下文环境是一个将模板变量名映射成Pyhton对象的字典;在浏览器中通过"polls"访问页面,如下图所示:

点击上图的链接,可以看到对应question的详细信息,如下图所示:

快捷方式:render()

Django提供了一个快捷方式:rendered template去加载模板,填充上下文环境并且返回HttpResponse对象,详细代码如下所示:

  1. from django.shortcuts import render
  2. from .models import Question
  3. def index(request):
  4. latest_question_list = Question.objects.order_by('-pub_date')[:5]
  5. context = {'latest_question_list': latest_question_list}
  6. return render(request, 'polls/index.html', context)

注:如果我们所有的视图函数都是按照上面这样实现的,就不需要再导入loader和HttpResponse了;如果视图函数还有detail,results,vote这几个方法的话,还是需要导入HttpResponse。

render()方法参数:request对象作为第一个参数,模板名作为第二个参数,上下文环境(字典)作为第三个可选择参数;它将根据给定的模板和上下文环境(字典)返回一个HttpResponse对象。

抛出404异常

为了更加丰富我们的视图函数,我们除了对正常情况的处理,还需要对异常进行处理,以视图中的detail()为例进行说明,其代码如下:

  1. from django.http import Http404
  2. from django.shortcuts import render
  3. from .models import Question
  4. # ...
  5. def detail(request, question_id):
  6. try:
  7. question = Question.objects.get(pk=question_id)
  8. except Question.DoesNotExist:
  9. raise Http404("Question does not exist")
  10. return render(request, 'polls/detail.html', {'question': question})

如果请求的ID不存在,该视图就会抛出Http404的异常,为了能够让该实例快速工作,再模板目录下添加polls/detail.html文件,其代码如下所示,具体讲解放在后面:

  1. {{ question }}

快捷方式:get_object_or_404()

通过get()获取的对象不存在,并且要抛出Http404异常的时候,Django提供了一种快捷方式,重写下面的detail()函数的代码:

  1. from django.shortcuts import get_object_or_404, render
  2. from .models import Question
  3. # ...
  4. def detail(request, question_id):
  5. question = get_object_or_404(Question, pk=question_id)
  6. return render(request, 'polls/detail.html', {'question': question})

get_object_or_404()方法参数:第一个参数为Django模型,其余参数是一系列关键字参数,这些参数将会传递给模型管理器的get()方法,如果获取的对象不存在,则抛出Http404异常。

在Django中还存在一个方法get_list_or_404(),其工作机制如同get_object_or_404(),最大的区别就是前者用filter()代替了后者的get(),并且前者在list为空的时候抛出异常。

回顾之前创建的detail()视图函数,在polls/detail.html文件中完善模板,代码如下:

  1. <h1>{{ question.question_text }}</h1>
  2. <ul>
  3. {% for choice in question.choice_set.all %}
  4. <li>{{ choice.choice_text }}</li>
  5. {% endfor %}
  6. </ul>

关于模板系统的更多使用,请参考

最后,我们需要在模板中删除硬编码的URLs

我们来回顾下polls/index.html模板中的链接的代码,如下所示:

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

在项目中拥有大量模板文件的时候,这种硬编码、紧耦合方式会存在使得对模板的修改变得异常困难(人力、时间、复杂性);幸运的是,在polls.urls模块的path()方法中,我们定义了关键字参数name,在模板里面我们就可以用{% url %}来替换掉具体的URLs路径,其代码如下:

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

工作机制:查找polls.urls模块中定义的特定URL,具体见下面代码:

  1. # name参数的值将会被模板的{% url %}标签调用
  2. path('<int:question_id>/', views.detail, name='detail'),

当我们想更改detail视图函数对应的URL时,我们可以不需要去修改模板文件,而只需要修改polls/urls.py文件即可,如下所示:

  1. # 添加前缀单词 'specifics'
  2. path('specifics/<int:question_id>/', views.detail, name='detail'),

URL名称的命名空间

在我们的mysite项目中,仅有一个应用:polls。但是,实际的Django项目中,可能会有5个,10个,20个甚至更多的应用。那么Django是如何在这些应用中区分URL的名字呢?举个例子:在polls应用中有个detail视图函数,同样的在该项目的blog中也有个detail视图函数。Django如何知道模板中的{% url %}标签,调用的是哪个应用的视图函数呢?

答案是:为URLconf添加namespaces。在polls/urls.py文件头部(导入模块下)添加一个app_name来设置应用的命名空间,代码如下所示:

  1. from django.urls import path
  2. from . import views
  3. app_name = 'polls'
  4. urlpatterns = [
  5. path('', views.index, name='index'),
  6. path('<int:question_id>/', views.detail, name='detail'),
  7. path('<int:question_id>/results/', views.results, name='results'),
  8. path('<int:question_id>/vote/', views.vote, name='vote'),
  9. ]

接下来,修改模板文件polls/index.html(指明detail视图的命名空间),代码如下所示:

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

Django 2.0 学习(06):Django 视图(进阶)的更多相关文章

  1. Django 2.0 学习(07):Django 视图(进阶-续)

    接Django 2.0 学习(06):Django 视图(进阶),我们将聚焦在使用简单的表单进行处理和精简代码. 编写简单表单 我们将用下面的代码,来替换之前的detail模板("polls ...

  2. Django 2.0 学习(03):Django视图和URL(下)

    接上篇博文,继续分析Django基本流程. 编写第一个(view)视图函数 1.打开文件polls/views.py,输入下面的Python代码: from django.http import Ht ...

  3. Django 2.0 学习(04):Django数据库

    数据库设置/配置 打开mysite/settings.py,我们会发现Django是用的是默认的数据库SQLite,如下图所示: Django也是支持其它数据库的,比如PostgreSQL.MySQL ...

  4. Django 2.0 学习(12):Django 模板语法

    Django 模板语法 一.模板 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板. 二.模板语法 模板语法变量:{{ }} 在Django模板中遍历复杂数据结构的关键是句点字 ...

  5. Django 2.0 学习(08):Django 自动化测试

    编写我们的第一个测试 确定bug 幸运的是,在polls应用中存在一个小小的bug急需修复:无论Question的发布日期是最近(最后)的日期,还是将来很多天的日期,Question.was_publ ...

  6. Django 2.0 学习(01):Django初识与安装

    Django(Python Web框架) Django是一个开放源代码的Web框架,用Python写的.采用了MTV的框架模式,即模型M,模板T和视图V.它最初被开发是用来管理以新闻内容为主的网站,即 ...

  7. Django 2.0 学习

    Django django是基于MTV结构的WEB框架 Model 数据库操作 Template 模版文件 View 业务处理 在Python中安装django 2.0 1 直接安装 pip inst ...

  8. Django 2.0 学习(19):Django 分页器

    Django 分页器 要使用Django实现分页功能,必须从Django中导入Paginator模块(painator - 分页器) views.py from django.shortcuts im ...

  9. Django 2.0 学习(13):Django模板继承和静态文件

    Django模板继承和静态文件 模板继承(extend) Django模板引擎中最强大也是最复杂的部分就是模板继承了,模板继承可以让我们创建一个基本的"骨架"模板,它可以包含网页中 ...

随机推荐

  1. 20145209刘一阳 《网络对抗》Exp7 网络欺诈技术防范

    20145209刘一阳 <网络对抗>Exp7 网络欺诈技术防范 一.应用SET工具建立冒名网站 要让冒名网站在别的主机上也能看到,需要开启本机的Apache服务,并且要将Apache服务的 ...

  2. Prism for WPF 搭建一个简单的模块化开发框架(六)隐藏菜单、导航

    原文:Prism for WPF 搭建一个简单的模块化开发框架(六)隐藏菜单.导航 这个实际上是在聊天之前做的,一起写了,也不分先后了 看一下效果图,上面是模块主导航,左侧是模块内菜单,现在加一下隐藏 ...

  3. EnterpriseDB公司的 Postgres Solution Pack (一)

    下载地址: http://www.enterprisedb.com/products-services-training/products/postgres-plus-solution-pack/do ...

  4. springBoot cache操作2

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zxd1435513775/article/details/85091793一.基本项目搭建测试项目是 ...

  5. android学习十三 首选项

    1,首选项可用用来持久保存用户设置,游戏最高分等 2,首选项有,列表首选项,复选框首选项,对话框首选项.. 3,通过xml文件和代码创建首选项      addPreferencesFromResou ...

  6. android 几个工具方法

    集合几个工具方法,方便以后使用. 1.获取手机 分辨率屏幕: public static void printScreenInfor(Context context){ DisplayMetrics ...

  7. 分享一个 UiPath Studio 相关的公众号

    RPA 和 UiPath 方面的资料比较少,因此我们自己创建了一个公众号,专门用于传播 UiPath 相关的知识. 会定期发布 UiPath 学习相关的信息.是目前难得的 UiPath 中文资源. 公 ...

  8. 程序迭代时测试操作的要点(后端&前端)

    今晚直播课内容简介,视频可点击链接免费听 <程序迭代时测试操作的要点(后端&前端)> ===== 1:迭代时后台涉及的操作有哪些?如何进行 a.更新war包:用于访问web\app ...

  9. 监控系统cpu相关统计信息

    背景:需要测试监控各个操作系统平台机器上的cpu相关的各种统计信息 为了方便测试,我写了一个比较通用的shell脚本,目前可以兼容Redhat6+,Redhat7+,其他操作系统没测,可以实时监控机器 ...

  10. 数据库Mysql的学习(八)-储存过程和事务和导入导出

    储存过程 DELIMITER // CREATE PROCEDURE pro1() BEGIN SELECT book_id,book_name,category FROM bookinfo t1 J ...