Django 系列官方教程[3]Views and templates

续第二章,这里开始创建视图

一、概述

视图是Django应用程序中的一种“类型”的网页,通常提供特定的功能并具有特定的模板。例如,在博客应用程序中,可能有以下视图:


博客主页–显示最新的几个条目。

条目“详细信息”页面–单个条目的永久链接页面。

基于年份的归档页面–显示给定年份中包含条目的所有月份。

基于月份的存档页面–显示给定月份中包含条目的所有日期。

基于日期的存档页面–显示给定日期的所有条目。

评论操作–处理向给定条目发布评论。


在我们的投票应用程序中,我们将有以下四种视图:


问题的“索引”页面–显示最新的几个问题。

问题“详细信息”页面–显示问题文本,没有结果,但带有投票表格。

问题“结果”页面–显示特定问题的结果。

投票操作–处理对特定问题中特定选项的投票。


在Django中,视图形成网页。每个视图都由一个Python函数(或方法,在基于类的视图中)表示。Django将通过检查请求的URL(准确地说,是URL中域名后的部分)来选择视图。


现在,在你的网络时代,你可能会遇到像ME2/Sites/dirmod.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B这样华丽的链接。Django都是可以识别的。


为了从URL到视图,Django使用了所谓的“URLconfs”。URLconf将URL模式映射到视图。

二、创建视图

打开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中添加path()调用

from django.urls import path

from . import views

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'),
]

这时我们可以在

http://127.0.0.1:8000/polls/1/

http://127.0.0.1:8000/polls/1/results/

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

分别看到我们创建的三个界面

Django会先在mysite.urls中找到polls/,并将1/results发送到polls/urls,所以polls.urls中为<int:question_id>/results/

三、创建视图内容
每个视图只有两种可能,返回HttpResponse对象或404.

视图可以从数据库中读取记录,也可以不读取。
可以使用Django之类的模板系统,也可以不使用第三方Python模板系统。
可以生成一个PDF文件,输出XML,动态创建一个ZIP文件,
使用任何你想要的Python库。

Django想要的只是HttpResponse

现在我们使用自带的数据库操作API来编写视图
打开polls/views.py,修改上半部分,detial、results和votes不变

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的模板系统,将视图和外观分离。

首先,在polls目录中创建一个名为templates的目录。Django将在那里寻找模板。

项目的模板设置描述Django将如何加载和呈现模板。默认设置文件配置一个DjangoTemplates后端,其APP_DIRS选项设置为True。按照惯例,DjangoTemplates会在每个已安装的应用程序中查找“templates”子目录。

在刚刚创建的templates目录中,创建另一个名为polls的目录,并在其中创建一个名为index.html的文件。换句话说,模板应该位于polls/templates/polls/index.html。由于app_目录模板加载器的工作原理如上所述,您可以在Django中将该模板称为polls/index.html.

现在我们更新polls/views.py,

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的模板。并将其传递给context.。context.是将模板变量名映射到Python对象的字典。


通过将浏览器指向“/polls/”加载页面,您应该会看到一个项目符号列表,其中包含教程2中的各类问题。链接指向问题的详细页面。

加载模板、填充context.并返回带有呈现模板结果的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})

为了快速验证我们添加页面polls/detail.html
 

{{ question }}

访问127.0.0.1:8000/polls/9999/验证。

五、get_object_or_404的简单写法
继续修改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(),而不是在更高级别上自动捕获ObjectDoesNotExist异常,或者让模型API引发Http404而不是ObjectDoesNotExist?

因为这会将模型层耦合到视图层。Django最重要的设计目标之一是保持松散耦合。

get_list_or_404() 是filter()层面的该指令,get_object_or_404()是get()的.

六、使用模板系统
现在我们来完善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对对象问题进行字典查找。如果做不到这一点,它会尝试属性查找——在本例中,这是有效的。如果属性查找失败,它会尝试列表索引查找。

{% for %} 循环方法调用,question.choice_set.all 会被编译器修改为question.choice_set.all(),从而返回Choice objects。

七、删除模板中的硬编码链接。
在polls/index.html中,链接被硬编码为:

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

这种硬编码、紧密耦合的方法的问题是,在具有大量模板的项目上更改URL会很复杂。但是,由于我们在polls.urls中的path()函数中定义了name参数。在URL模块中,我们可以使用{%URL%}模板标记删除对URL配置中定义的特定URL路径的依赖:

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

我们可以在polls.urls中看到这个定义:

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

八、设定名称域

真实的项目中,我们可能会遇到很多个app而不是仅有一个polls,那么{% url %}要怎么识别每个应用的detail页面呢?

所以我们需要设置一个姓名域。我们需要在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'),
]


现在将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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值