学学笔记 - 官方 Qiter | 学习笔记

Django4 - 第一个项目案例代码 第四节

发布时间:9个月前热度: 149 ℃评论数:

一个快捷函数: 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)

注意到,我们不再需要导入 ​loader和 ​HttpResponse ​。不过如果你还有其他函数(比如说 ​detail​, ​results​, 和 ​vote ​)需要用到它的话,就需要保持 ​HttpResponse ​的导入。

抛出404错误

现在,我们来处理投票详情视图——它会显示指定投票的问题标题。下面是这个视图的代码:

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

这里有个新原则。如果指定问题 ID 所对应的问题不存在,这个视图就会抛出一个 ​Http404 ​异常。
我们稍后再讨论你需要在 ​polls/detail.html​ 里输入什么,但是如果你想试试上面这段代码是否正常工作的话,你可以暂时把下面这段输进去:
{{ question }}

一个快捷函数: get_object_or_404()

尝试用 ​get()​ 函数获取一个对象,如果不存在就抛出 ​Http404 ​错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 ​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​。

也有 ​get_list_or_404()​ 函数,工作原理和 ​get_object_or_404()​ 一样,除了 ​get()​ 函数被换成了 ​filter()​ 函数。如果列表为空的话会抛出 ​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 }}​ 中,首先 Django 尝试对 ​question ​对象使用字典查找(也就是使用 ​obj.get(str)​ 操作),如果失败了就尝试属性查找(也就是 ​obj.str​ 操作),结果是成功了。如果这一操作也失败的话,将会尝试列表查找(也就是 ​obj[int]​ 操作)。
在 ​{% for %}​ 循环中发生的函数调用:​question.choice_set.all​ 被解释为 Python 代码 ​question.choice_set.all()​ ,将会返回一个可迭代的 ​Choice ​对象,这一对象可以在​ {% for %} ​标签内部使用。

去除模板中的硬编码URL

还记得吗,我们在 ​polls/index.html里编写投票链接时,链接是硬编码的:

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

问题在于,硬编码和强耦合的链接,对于一个包含很多应用的项目来说,修改起来是十分困难的。然而,因为你在 ​polls.urls​ 的 ​url()​ 函数中通过 ​name参数为 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/specifics/12/ ​,你不用在模板里修改任何东西(包括其它模板),只要在 ​polls/urls.py​ 里稍微修改一下就行:

...
# added the word 'specifics'
path('specifics/<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>

Django4 - 第一个项目案例代码 第四节

栏目导航

  1. Django
  2. Pandas
  3. PyQt5

手机扫码访问