Django 学习 Part 3: 视图与模板系统
本教程基于 Django 6.0 官方文档承接第二部分的数据库模型深入讲解 Django 的视图Views和模板系统Templates。一、什么是视图在 Django 中视图View是网页的一种类型负责接收 Web 请求并返回 Web 响应。每个视图函数都必须做两件事之一返回一个包含被请求页面内容的HttpResponse对象抛出一个异常如Http4041.1 规划我们的投票应用视图在我们的polls应用中需要实现以下四个视图视图功能URL 模式描述问题索引页/polls/展示最近的几个投票问题问题详情页/polls/id/展示某个投票的问题和选项列表问题结果页/polls/id/results/展示某个投票的结果投票处理器/polls/id/vote/处理用户投票操作二、编写更多视图2.1 基础视图函数在polls/views.py中我们之前只有一个简单的index视图。现在让我们添加更多视图fromdjango.httpimportHttpResponsedefindex(request):returnHttpResponse(Hello, world. Youre at the polls index.)defdetail(request,question_id):returnHttpResponse(fYoure looking at question{question_id}.)defresults(request,question_id):returnHttpResponse(fYoure looking at the results of question{question_id}.)defvote(request,question_id):returnHttpResponse(fYoure voting on question{question_id}.)2.2 配置 URL 路由更新polls/urls.py文件添加新的 URL 模式fromdjango.urlsimportpathfrom.importviews urlpatterns[# 首页展示问题列表path(,views.index,nameindex),# 详情页展示特定问题path(int:question_id/,views.detail,namedetail),# 结果页展示投票结果path(int:question_id/results/,views.results,nameresults),# 投票处理path(int:question_id/vote/,views.vote,namevote),]关键点解析int:question_id使用路径转换器捕获 URL 中的整数参数捕获的值会作为关键字参数传递给视图函数参数名必须与视图函数参数名完全一致2.3 URL 解析机制当用户访问/polls/20/时Django 的 URL 解析流程如下Django 从ROOT_URLCONF即mysite/urls.py开始匹配匹配到polls/前缀截断后将剩余部分20/转发到polls.urls在polls/urls.py中int:question_id/匹配成功捕获20作为question_id20调用views.detail(request, question_id20)三、编写真正有用的视图3.1 从数据库获取数据让我们改造index视图使其展示数据库中的最新问题fromdjango.httpimportHttpResponsefrom.modelsimportQuestiondefindex(request):# 获取按发布日期排序的最新5个问题latest_question_listQuestion.objects.order_by(-pub_date)[:5]# 将问题文本用逗号连接output, .join([q.question_textforqinlatest_question_list])returnHttpResponse(output)问题页面设计硬编码在 Python 代码中修改页面需要编辑代码。这违反了关注点分离原则。3.2 引入模板系统Django 的模板系统允许我们将页面设计与 Python 代码分离。步骤 1创建模板目录在polls目录下创建以下结构polls/ templates/ polls/ index.html注意在templates目录内再创建一个polls子目录是最佳实践。Django 通过这种方式确定使用哪个应用的模板。步骤 2编写模板文件创建polls/templates/polls/index.html!DOCTYPEhtmlhtmlheadtitle投票应用/title/headbody{% if latest_question_list %}ul{% for question in latest_question_list %}liahref/polls/{{ question.id }}/{{ question.question_text }}/a/li{% endfor %}/ul{% else %}pNo polls are available./p{% endif %}/body/html模板语法说明{% if %}/{% for %}模板标签用于逻辑控制{{ variable }}变量插值显示动态内容question.choice_set.all通过外键反向查询关联对象步骤 3在视图中使用模板fromdjango.httpimportHttpResponsefromdjango.templateimportloaderfrom.modelsimportQuestiondefindex(request):latest_question_listQuestion.objects.order_by(-pub_date)[:5]# 加载模板templateloader.get_template(polls/index.html)# 构建上下文context{latest_question_list:latest_question_list,}# 渲染模板并返回 HttpResponsereturnHttpResponse(template.render(context,request))3.3 快捷函数render()“加载模板、填充上下文、返回 HttpResponse” 是非常常见的流程Django 提供了快捷函数fromdjango.shortcutsimportrenderfrom.modelsimportQuestiondefindex(request):latest_question_listQuestion.objects.order_by(-pub_date)[:5]context{latest_question_list:latest_question_list}returnrender(request,polls/index.html,context)render()函数参数request请求对象template_name模板名称context可选字典形式的上下文数据四、处理 404 错误4.1 手动抛出 Http404当请求的问题不存在时应该返回 404 错误fromdjango.httpimportHttp404fromdjango.shortcutsimportrenderfrom.modelsimportQuestiondefdetail(request,question_id):try:questionQuestion.objects.get(pkquestion_id)exceptQuestion.DoesNotExist:raiseHttp404(Question does not exist)returnrender(request,polls/detail.html,{question:question})创建polls/templates/polls/detail.htmlh1{{ question.question_text }}/h1ul{% for choice in question.choice_set.all %}li{{ choice.choice_text }}/li{% endfor %}/ul4.2 快捷函数get_object_or_404()手动捕获DoesNotExist异常很繁琐Django 提供了更优雅的解决方案fromdjango.shortcutsimportget_object_or_404,renderfrom.modelsimportQuestiondefdetail(request,question_id):questionget_object_or_404(Question,pkquestion_id)returnrender(request,polls/detail.html,{question:question})设计哲学为什么使用get_object_or_404()而不是让模型 API 直接抛出Http404这样做会增加模型层和视图层的耦合性。Django 最重要的设计思想之一是保证松散耦合。一些受控的耦合被包含在django.shortcuts模块中。五、去除模板中的硬编码 URL5.1 问题分析当前index.html中的链接是硬编码的ahref/polls/{{ question.id }}/{{ question.question_text }}/a这会导致维护困难——如果 URL 结构改变需要修改所有模板文件。5.2 使用 url 模板标签Django 提供了{% url %}标签通过 URL 配置中的name参数反向解析 URLliahref{% url detail question.id %}{{ question.question_text }}/a/li工作原理detail对应urls.py中namedetail的 URL 模式question.id作为参数传递给视图函数六、URL 命名空间6.1 问题背景在实际项目中可能有多个应用如polls、blog、shop每个应用都可能有名为detail的视图。Django 如何区分它们6.2 添加应用命名空间在polls/urls.py中添加app_namefromdjango.urlsimportpathfrom.importviews app_namepolls# 设置应用命名空间urlpatterns[path(,views.index,nameindex),path(int:question_id/,views.detail,namedetail),path(int:question_id/results/,views.results,nameresults),path(int:question_id/vote/,views.vote,namevote),]6.3 使用命名空间 URL更新模板使用polls:detail语法ahref{% url polls:detail question.id %}{{ question.question_text }}/a这样即使多个应用有同名的 URLDjango 也能准确识别。七、完整代码汇总polls/views.pyfromdjango.shortcutsimportrender,get_object_or_404fromdjango.httpimportHttpResponsefrom.modelsimportQuestiondefindex(request):首页展示最新5个问题latest_question_listQuestion.objects.order_by(-pub_date)[:5]context{latest_question_list:latest_question_list}returnrender(request,polls/index.html,context)defdetail(request,question_id):详情页展示问题及选项questionget_object_or_404(Question,pkquestion_id)returnrender(request,polls/detail.html,{question:question})defresults(request,question_id):结果页展示投票结果questionget_object_or_404(Question,pkquestion_id)returnrender(request,polls/results.html,{question:question})defvote(request,question_id):处理投票# 将在第四部分实现returnHttpResponse(fYoure voting on question{question_id}.)polls/urls.pyfromdjango.urlsimportpathfrom.importviews app_namepollsurlpatterns[path(,views.index,nameindex),path(int:question_id/,views.detail,namedetail),path(int:question_id/results/,views.results,nameresults),path(int:question_id/vote/,views.vote,namevote),]结果模板文件结构polls/ templates/ polls/ index.html # 问题列表页 detail.html # 问题详情页 results.html # 投票结果页参考资源Django 6.0 官方文档 - 编写你的第一个 Django 应用第 3 部分Django 模板语言文档
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2420096.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!