Django基础3-视图和模版

版权声明:本文为博主原创文章,欢迎转载。 https://blog.csdn.net/fww330666557/article/details/82955584

概述

在Django应用中,视图是网页的“类型”,通常用于特定功能并具有特定模板。例如在博客应用中,可能包含以下视图:
博客主页:显示最新的几个条目;
详情页面:单个条目的永久连接;
基于年份的存档页面:显示给定年份包含条目的所有月份;
基于月份的存档页面:显示给定月份中包含条目的所有日期;
基于日期的存档页面:显示给定日期的所有条目;
评论操作:处理对给定条目的发布评论。

在我们的投票应用中,我们有以下四个视图:
问题“索引”页面 - 显示最新的几个问题。
问题“详情”页面 - 显示问题文本,没有结果,但有投票表单。
问题“结果”页面 - 显示特定问题的结果。
投票操作 - 在特定问题中,处理针对特定选择的投票。

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

现在在网络上你可能遇到过“ME2 / Sites / dirmod.asp?sid =&type = gen&mod = Core + Pages&gid = A6CD4967199A42D9B65B1B”等。 令人庆幸的是Django允许我们使用比这更优雅的URL模式。

为了从URL获得视图,Django使用了所谓的’URLconf’。 URLconf将URL模式映射到视图。
本教程提供了使用URLconf的基本说明,您可以参考“URL调度器”了解更多信息。

设置更多视图

现在我们再添加一些视图到polls/views.py。 这些视图与index视图相比略微不同,因为它们有一个参数:

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")
    
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)

通过添加以下path()调用,将这些新视图连接到polls.urls模块中:

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

让视图做些实质的事情

每个视图的响应都会做两件事中的一件:返回一个HttpResponse对象或抛出一个类似Http404的异常。
下面是一个新的index()视图,它显示系统中最新的5个轮询问题,根据出版日期,用逗号分隔:

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的模版系统,将python的设计和视图的设计分离出来。

首先在polls目录下,创建一个名为templates 的目录。 Django将在该目录下寻找模版。
你的项目中的TEMPLATES设置描述Django如何加载和渲染模版。默认设置文件配置一个DjangoTemplates后端,该后端的APP_DIRS选项被设置为True。按惯例,DjangoTemplates在每一个INSTALLED_APPS中寻找‘templates’子目录。

在你刚刚创建的templates目录中,创建另一个名为polls的目录,然后创建一个名为index.html的文件。换句话说,你的模版应该位于polls/templates/polls/index.html 。由于上述的app_directories template loader的工作原理,你可以简单滴以polls/index.html的形式访问该模版。

在模版中添加如下内容:

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

现在让我们使用模版来升级我们的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。该context是一个字典,将模版变量名和python对象进行映射。

一个快捷方式: render()

加载一个模版,填充一个context,然后返回一个包含模版渲染结果的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()函数将request对象作为第一个参数,将模板名称作为第二个参数,将字典作为可选的第三个参数。It returns an HttpResponse object of the given template rendered with the given context.

编写一个404视图

现在,让我们来处理 detail 视图 ,这是视图内容:

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

The new concept here: The view raises the Http404 exception if a question with the requested ID doesn’t exist.

We’ll discuss what you could put in that polls/detail.html template a bit later, but if you’d like to quickly get the above example working, a file containing just:

polls/templates/polls/detail.html:

{{ question }}

快捷方式:get_object_or_404()

It’s a very common idiom to use get() and raise Http404 if the object doesn’t exist. Django provides a shortcut. Here’s the detail() view, rewritten:

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()函数。 It raises Http404 if the object doesn’t exist.

哲学:
为什么我们要使用一个辅助函数get_object_or_404()而不是在更高层自动捕获ObjectDoesNotExist异常,或者让模型的API 引发 Http404 而不是ObjectDoesNotExist?
Because that would couple the model layer to the view layer.
 One of the foremost design goals of Django is to maintain loose coupling. 
 Some controlled coupling is introduced in the django.shortcuts module.

还有一个get_list_or_404()函数,它的工作方式类似get_object_or_404() —— 差别在于它使用filter()而不是get()。 It raises Http404 if the list is empty.

使用模版系统

回到我们的poll应用的detail()视图 . polls/detail.html 模版如下所示:

polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

模版系统使用 dot-lookup 语法访问变量属性. 在{{ question.question_text }}这个例子中,Django首先在question对象上做字典查询。 Failing that, it tries an attribute lookup – which works, in this case. If attribute lookup had failed, it would’ve tried a list-index lookup.

方法调用发生在{% for %}循环中:question.choice_set.all被解释为Python的代码question.choice_set.all(),它返回一个由Choice对象组成的可迭代对象,并将其用于{% for %}标签。

See the template guide for more about templates.

移除模版中写死的URL

记得吗?在polls/index.html模板中,我们连接到polls的链接是硬编码成这个样子的:

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

问题出在硬编码,紧耦合使得在大量的模板中修改 URLs 成为富有挑战性的项目。 然而,因为你在polls.urls模块的url()函数中定义了name 参数,你可以通过使用{% url %}模板标签来移除对你的URL配置中定义的特定的URL的依赖:

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

The way this works is by looking up the URL definition as specified in the polls.urls module. You can see exactly where the URL name of ‘detail’ is defined below:

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

如果你想修改polls应用的detail视图的URL, 类似于polls/specifics/12/的形式,你可以修改polls/urls.py中的内容:

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

URL名称的命名空间

The tutorial project has just one app, polls. In real Django projects, there might be five, ten, twenty apps or more. How does Django differentiate the URL names between them? 例如,polls应用程序具有详细信息视图,因此同一个项目中的应用程序可能适用于博客。 如何让Django知道在使用{% url %}时为网址创建哪个应用视图模板标签?

答案是将命名空间添加到您的URLconf中。 In the polls/urls.py file, go ahead and add an app_name to set the application namespace:

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>

猜你喜欢

转载自blog.csdn.net/fww330666557/article/details/82955584
今日推荐