Django快速入门-视图

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

博客首页 - 显示最后的几个文章。 进入“detail”页面- 对单个项目永久链接页面。 存档页 - 显示所有在给定年份各月的条目。 月存档页 - 显示所有给定月份各天的所有项。 天存档页 - 显示某一天所有条目。 评论操作 - 处理发布评论的一个给定输入。

在我们的 poll 应用程序,有以下四个视图:

问题的“index”页- 显示最后几个问题。 问题的“detail”页 - 显示一个问题文本,没有结果但有一个表单用来投票。 问题的“results”页面 - 显示结果一个特定问题。 投票操作 - 处理投票在一个特定的问题进行具体选择。

在Django中,网页和其他内容由视图提供。每个视图由一个简单的Python函数来表示(或方法,基于类的视图)。Django会选择一个视图通过考察多数民众赞成请求的URL(准确地说,在域名之后URL的一部分)。

一个URL模式是一个简单的URL的一般形式 - 例如:/newsarchive/<year>/<month>/.

编写更多的视图

现在,让我们添加一些视图在 polls/views.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 模块中如下的 url() 调用,polls/urls.py文件中的代码如下:

from django.conf.urls import url

from . import views

urlpatterns = [
 # ex: /polls/
    url(r'^$', views.index, name='index'),
 # ex: /polls/5/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
 # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
 # ex: /polls/5/vote/
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

您可以在浏览器打开“/polls/34/”。它会运行detail()方法,并显示任何提供的URL内容。 再次尝试访问 “/polls/34/results/” and “/polls/34/vote/”  – 这将显示占位符结果和投票页面。

include() 可以很容易包含入插件和网址。因为polls是在它们自己的URL配置(polls/urls.py),它们可以放置在“/polls/”,或 “/fun_polls/”,或在“/content/polls/”,或任何其它路径的根,应用程序仍然可以工作。

下面是如果用户进入“/polls/34/”,在这个系统会发生什么:

Django会找到匹配'^polls/' 然后,Django会去掉匹配的文本("polls/")

并发送剩余的文本 – "34/" – 到'polls.urls'URL配置用于进一步处理相匹配 r'^(?P<question_id>[0-9]+)/$'从而调用detail() 视图,如下所示:

detail(request=<HttpRequest object>, question_id='34')

question_id='34' 是来自 (?P<question_id>[0-9]+)的一部分,用周围的模式括号“捕捉”匹配该模式文本,并将其作为参数传递给视图函数;  ?P<question_id> 定义了将被用来识别所述匹配的模式的名称;  以及[0-9]+ 正则表达式匹配一个数字序列(在一个数字)。

由于URL模式是正则表达式,可以使用它来做一些事情,没有任何限制。而且也没有必要添加URL为.html – 除非你想,在这种情况下,你可以这样做:

url(r'^polls/latest\.html$', views.index),

编写视图实现功能

每个视图负责做两件事情之一:返回包含所请求的页面内容的 HttpResponse 对象,或抛出一个异常,如HTTP 404。 修改polls/views.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

在这里有一个问题就,通过:网页设计是硬编码在视图中。如果想改变页面的样子,必须编辑这个 Python 代码。因此,让我们使用 Django 模板系统通过创建视图可以使用模板来分开Python 的代码。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,然后传递给它的上下文。上下文是一个字典以Python对象映射模板变量名。现在访问URL(http://127.0.0.1:8000/polls/)查看结果 :

浏览器运行结果

快捷方式: render()

这是一个非常习惯用法来加载模板,填充上下文中和渲染模板的结果返回一个HttpResponse对象。Django提供了一个捷径。下面是完整的index() 视图,改写polls/views.py为:

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)

请注意,当在各个视图做到了这一点,我们不再需要导入加载器和HttpResponse对象(想保留HttpResponse,如果仍然有短截 detail, results, 和 vote 方法。

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

注意这里:视图引发HTTP404异常,如果与请求ID的问题并不存在。

我们将讨论可以把 polls/detail.html 在后面做一些修改,但如果想快速使用上面的实例,polls/templates/polls/detail.html 文件只需包含:


   {{question}}

浏览器运行结果
引发 404 错误,现在我们请求一个不存在问题,如:http://127.0.0.1:8000/polls/100/,显示结果如下:

浏览器运行结果

快捷方式: get_object_or_404()

如果对象不存在的一个非常习惯用法使用get()并引发HTTP404错误。Django提供了一个捷径。下面是 detail() 视图,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()函数接受一个Django模型作为第一个参数和关键字任意参数数量,它传递到模型管理的 get()函数。

如果对象不存在将引发HTTP404。

还有一个get_list_or_404()函数,它的工作原理就像get_object_or_404()- 除了使用 filter()而不是get()方法。如果列表是空的它会引起HTTP404。

使用模板系统

回到我们的 polls 应用程序 detail() 视图。由于上下文变量的问题,这里的 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对象字典查找。 如果找不到,它再尝试属性查询 – 如果属性查找失败,它会尝试一个列表索引查找。
现在测试我们上面编写的代码,在浏览器中打开:http://127.0.0.1:8000/polls/5/ 得到结果如下:
浏览器运行结果

删除模板硬编码网址

请记住,当我们在 polls/index.html 链接到一个问题,链接被硬编码的部分是这样的:

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

使用此硬编码,紧密耦合的方法的问题是:它在更改项目的URL用了很多模板。不过,既然 polls.urls模块中定义名称参数url() 函数,您可以通过使用 {% url %}模板删除标签在URL配置中定义的特定URL路径的依赖:

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

这种工作方式是通过为polls.urls模块中指定查找的URL定义。可以准确地看到'detail'的URL名称定义如下:

  ...
# the 'name' value as called by the {% url %} template tag
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

如果你想要把投票详细视图的URL更改成其它的,也许像 polls/specifics/12/ 取代在模板(或templates),需要在 polls/urls.py 改变它:

  ...
# added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...

命名空间URL名称

本教程项目只有一个应用程序 - polls。在实际的Django项目中,可能有五个,十个,二十个或更多的应用程序。Django 如何区分它们的URL的名称? 例如,投票应用程序有一个详细视图,因此可能会在一个博客的同一个项目也有相同的应用程序。如何使用 {% url %} 模板标签让Django知道创建一个URL哪些应用有这样视图?

答案就是将命名空间添加到URLconf。在polls/urls.py文件,继续前进,添加应用程序名称设置应用程序命名空间,打开 polls/urls.py:

from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

现在修改 polls/index.html 模板,打开 polls/templates/polls/index.html 文件添加以下代码:

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

使其指向在命名空间 detail 视图,打开 polls/templates/polls/index.html 文件如下:

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