033创建视图(功能模块)

视图的概念是「一类具有相同功能和模板的网页的集合」,每一个视图表现为一个 Python 函数(或者说方法,如果是在基于类的视图里的话)。Django 将会根据用户请求的 URL 来选择使用哪个视图(更准确的说,是根据 URL 中域名之后的部分)。

在我们的投票应用中,我们需要下列几个视图:

  • 索引页——展示最近的几个投票问题。
  • 问题详情页——展示某个投票的问题和不带结果的选项列表。
  • 问题结果页——展示某个投票的结果。
  • 投票处理器——用于响应用户为某个问题的特定选项投票的操作。

新增视图,显示详情/结果等

在polls/views.py里添加3个视图。

即: 详情/结果查询和投票响应。注意,这里都带了参数2

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模块

from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    #下面新增详情/结果/投票查询
    # ex: /polls/5/ 
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

这个时候,就可以响应3种页面了,如下:

  • 问题详情页
    这里查询的是第100个问题,其实任意取
    在这里插入图片描述

  • 查看100号问题的投票结果页
    在这里插入图片描述

  • 查看100号问题 的投票响应页
    在这里插入图片描述
    这是当前用于占位的结果和投票页。这个查询和响应的经过是:

“/polls/100/” ,Django 将会载入 mysite.urls 模块,因为这在配置项 ROOT_URLCONF 中设置了。然后 Django 寻找名为 urlpatterns 变量并且按序匹配正则表达式。在找到匹配项 ‘polls/’,它切掉了匹配的文本(“polls/”),将剩余文本——“100/”,发送至 ‘polls.urls’ URLconf 做进一步处理。在这里剩余文本匹配了 ‘int:question_id/’,使得我们 Django 以如下形式调用 detail():detail(request=<HttpRequest object>, question_id=100)


question_id=100 部分来自 int:question_id。 使用尖括号“捕获”URL 的一部分并将其作为关键字参数发送给视图函数。 字符串的 question_id 部分定义了用于标识匹配模式的名称,int 部分是一个转换器,用于确定哪些模式应该与 URL 路径的这一部分匹配。 冒号 : 分隔转换器和模式名称。

改进索引页输出结果

查询数据库并输出
每个视图必须要做的只有两件事:返回一个包含被请求页面内容的HttpResponse 对象,或者抛出一个异常,比如 Http404 。

索引页: 展示最近5个投票问题

使用Django 自带的数据库 API ,在 index() 函数里插入一些新内容,让它能展示数据库里以发布日期排序的最近 5 个投票问题,以空格分割.

  • 更改polls.view.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)
    
# Leave the rest of the views (detail, results, vote) unchanged

重新展示索引页:
在这里插入图片描述

使用 templates ,加入index.html

这里有个问题:页面的设计写死在视图函数的代码里的。但是,如果使用 Django 的模板系统,只要创建一个视图,就可以将页面的设计从代码中分离出来。

  • 创建步骤如下:

首先,在你的 polls目录里创建一个 templates 目录。Django 将会在这个目录里查找模板文件。
在创建的 templates 目录里,再创建一个目录 polls,然后在其中新建一个文件 index.html .
现在路径是: polls/templates/polls/index.html , Django 可以引用到 polls/index.html 这一模板了。

- 为什么呢?
> 应用名:polls,  模板文件名:index;  模板文件index.html
> 为了避免不同的应用,都用index这个名字,我们要分开,即:把这些模板放入一个和 自身 应用重名的子文件夹里。
> 使用时,用 `polls/index.html`	的形式
  • 打开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 %}

上述代码的作用是:

如果列表不为空,就遍历各项,输出各项的question_text
若列表为空,则输出No polls are available.


注意,这里是个链接:href="/polls/{{ question.id }},后面补上看这里
html函数的参考:模板指南

  • 然后,更新一下 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)。这个上下文是一个字典,它将模板内的变量映射为 Python 对象。
在这里插入图片描述

使用 render 改写3板斧

「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。于是 Django 提供了一个快捷函数:

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)

render函数省略了 loaderHttpResponse 的使用
注意:

render函数的参数,分别是请求对象request,模板名称’polls/index.html’和字典context

详情页可能抛出404

改写 detail 函数

如果指定问题 ID 所对应的问题不存在,这个视图就会抛出一个 Http404 异常。

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

detail.html页面占位

新建 polls/detail.html,暂时写入

{{ question }}

测试一下:

  • 存在数据项的的时候
    在这里插入图片描述
  • 不存在数据项 的时候
    在这里插入图片描述

使用 get_object_or_404 改写detail

get获取一个对象,如果不存在就抛出 Http404 错误,可以简写:

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

参数与render函数一致. 此外可以看到:

一些受控的耦合将会被包含在 django.shortcuts 模块中。
也有 get_list_or_404() 函数,工作原理和 get_object_or_404() 一样,除了 get() 函数被换成了 filter() 函数。如果列表为空的话会抛出 Http404 异常。

  • 改写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依次进行:

字典查找(也就是使用 obj.get(str) 操作): question.get(question_text)
属性查找(也就是 obj.str 操作): question.question_text
列表查找(也就是 obj[int] 操作): question[question_id]

在 {% for %} 循环中发生的函数调用:

question.choice_set.all 被解释为 Python 代码 question.choice_set.all() ,将会返回一个可迭代的 Choice 对象,这一对象可以在 {% for %} 标签内部使用。

其他问题

HTML中的for和属性是怎么回事?

在HTML页面编写Django模板语言,参见:模板指南

不怕换网址的内部路径了


为了避免应用内部路径改变,需要改进模板 url 为软编码。先看之前的:

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

这里的HTML链接1是硬编码的.硬编码和强耦合的链接,对于一个包含很多应用的项目来说,修改起来是十分困难的。
然而,因为你在 polls.urls 的 url() 函数中通过 name 参数为 URL 定义了名字,即

path('<int:question_id>/', views.detail, name='detail'),
  • 这下,你可以使用 {% url %} 标签代替它:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

这下,记为HTML链接2.
之后就不怕改网页链接了,比如 polls.urls 的 url() 函数中改成:

path('specifics/<int:question_id>/', views.detail, name='detail'),

即用 polls/specifics/100/ 来访问.
这也可以不用再改上面的HTML链接2

软连接name参数可能重名

polls 应用有 detail 视图,可能另一个博客应用也有同名的视图。Django 如何知道 {% url %} 标签到底对应哪一个应用的 URL 呢?
这需要在根 URLconf 中添加命名空间。

  • 在 polls/urls.py 文件中稍作修改,加上 app_name 设置命名空间:
from django.urls import path

from . import views

app_name = 'polls'		# 新增一行
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/results/', views.results, name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
  • 那么,HTML链接2也需要对应的,加上这个命名空间了:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值