【Django第一步】第三部分:视图和模板

【Django第一步】第三部分:视图和模板

@[Django| 翻译| python]

我们继续完成web应用程序,并且把重点放到创建公共接口——视图

概述

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

博客主页 - 显示最新的几个条目。
- 输入“详细信息”页面 - 永久链接页面用于单个条目。
- 基于年份的存档页面 - 显示给定年份中所有条目的月份。
- 基于月份的归档页面 - 显示给定月份中所有日期的条目。
- 基于日期的归档页面 - 显示给定日期的所有条目。
- 评论操作 - 处理对给定条目的发布评论。

在我们的投票应用程序中,我们将拥有以下四个视图:
- 问题“索引”页面 - 显示最新的几个问题。
- 问题“详细信息”页面 - 显示问题文本,没有结果,但有投票表格。
- 问题“结果”页面 - 显示特定问题的结果。
- 投票行动 - 在特定问题中处理针对特定选择的投票。

在Django中,网页和其他内容由视图传递。每个视图都由一个简单的Python函数(或基于类的视图的方法)表示。Django将通过检查请求的URL(准确地说,域名后面的URL部分)来选择一个视图。

现在,在网络上,您可能遇到过诸如“ME2 / Sites / dirmod.asp?sid =&type = gen&mod = Core + Pages&gid = A6CD4967199A42D9B65B1B”等链接。你会很高兴知道Django允许我们使用比这更优雅的 URL模式。

URL模式只是URL的一般形式 - 例如: /newsarchive/<year>/<month>/

为了从URL获得视图,Django使用了所谓的’URLconf’。URLconf将URL模式映射到视图。

本教程提供了有关使用URLconf的基本说明,您可以参考URL调度程序以获取更多信息。

更多的视图

现在让我们在polls/view.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中添加path()将新视图链接进去

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

看看你的浏览器,在“/ polls / 1 /”。它会运行该detail() 方法并显示您在URL中提供的任何ID。尝试“/ polls / 1/ results /”“/ polls / 1 / vote /” - 这些将显示占位符结果和投票页面。

当有人从你的网站请求一个页面 - 比如“/ polls / 1 /”时,Django会加载mysite.urlsPython模块,因为它是由ROOT_URLCONF设置指向的 。它找到名为的变量urlpatterns 并按顺序遍历模式。找到匹配后'polls/',它会去掉匹配的文本("polls/"),并将剩余的文本 - 发送 “1/”到“polls.urls”URLconf以供进一步处理。在那里匹配'<int:question_id>/',导致对detail()视图的调用如此:

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

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

编写可以执行某些操作的视图

每个视图负责执行以下两项操作之一:返回 HttpResponse包含所请求页面的内容的 对象,或引发异常,如Http404。其余的由你决定。

您的视图可以从数据库中读取记录,或不是。它可以使用模板系统,例如Django’s - 或第三方Python模板系统 - 也可以不使用。它可以生成一个PDF文件,输出XML,随时创建一个ZIP文件,任何你想要的,使用任何你想要的Python库。

Django想要的就是这个HttpResponse,因为它十分方便,所以我们使用Django自己的数据库API,我们在教程2中介绍了它。index() 根据出版日期,这是一个新视图,它显示系统中最新的5个投票问题,中间用逗号分隔

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

但是这有一个额问题,页面的设计出现在view.py中 ,如果你想改变页面的外观,必需编辑这个文件。因此,我们使用Django的模板系统创建视图,可以使模板设计与Python分离。

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

您的项目TEMPLATES设置描述了Django如何加载和呈现模板。

templates创建的目录中,创建另一个名为的目录polls,并在其中创建一个名为的文件 index.html。换句话说,你的模板应该在 polls/templates/polls/index.html。您可以在Django中简单地引用此模板polls/index.html。

模板命名空间
现在我们可以避免将模板直接放入 polls/templates(而不是创建另一个polls子目录),但这实际上是一个糟糕的主意。Django会选择找到的名称匹配的第一个模板,如果在不同的应用程序中有同名的模板,Django将无法区分它们。我们需要能够将Django指向正确的位置,并且最简单的方法是通过对它们进行命名来确保它是正确的。也就是说,将这些模板放在为应用程序本身命名的另一个目录中。

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中使用模板:

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是一个将模板变量名称映射到Python对象的字典。

通过将浏览器指向“/ polls /”来加载页面,并且您应该看到一个包含教程2中 “What’s up”问题的项目符号列表。链接指向问题的详细信息页面。

捷径:render()

加载模板,填充上下文并返回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)

该render()函数将请求对象作为其第一个参数,将模板名称作为其第二个参数,并将字典作为其可选的第三个参数。它返回HttpResponse 给定模板呈现给定上下文的对象

抛出404错误

现在,让我们查看Question的详细信息视图 - 显示给定投票的问题文本的页面。这是视图:

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的问题不存在,则视图引发异常。

我们将在稍后讨论可以放在该polls/detail.html模板中的内容,但如果您想快速获得上述示例的工作方式,则只需包含以下内容的文件:

添加detail.html视图

{{  question  }}

捷径:get_object_or_404()

可以将detail改写为:

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如果对象不存在,则会引发。

使用模板系统

回到detail()我们的投票应用程序的视图。鉴于上下文变量question,以下是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 }}question

方法调用发生在循环中: 被解释为Python代码 ,它返回一系列对象并适合在标记中使用。{% for %}question.choice_set.allquestion.choice_set.all()Choice{% for %}

删除硬编码的网址模板

当我们在polls/index.html 模板中编写问题链接时,链接部分硬编码如下:

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

这种硬编码,紧密耦合的方法存在的问题是,在具有大量模板的项目上更改网址变得非常具有挑战性。但是,由于您path()在polls.urls模块中的函数中定义了name参数,因此可以使用模板标记删除对URL配置中定义的特定URL路径的依赖:{% url %}

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

它的工作方式是通过查找polls.urls模块中指定的URL定义 。您可以在下面定义具体的’detail’的URL名称:

...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...

命名空间URL名称

该教程项目只有一个应用程序,polls。在真正的Django项目中,可能会有五个,十个,二十个应用程序或更多。Django如何区分它们之间的URL名称?例如,该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'),
]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值