django初学教程 投票应用 03 创建视图

https://docs.djangoproject.com/zh-hans/3.2/intro/tutorial03/

URL调度器

django视图-菜鸟教程

视图

视图函数,简称视图,是一个简单的python函数,接受Web请求并返回Web响应,一般放在项目的views.py文件中。

视图中有两个重要的对象:请求对象(HttpRequest)与响应对象(HttpResponse)。

HttpResponse对象中包含生成的响应。

投票项目视图:

  • 问题索引页——展示最近的几个投票问题。
  • 问题详情页——展示某个投票的问题和不带结果的选项列表。
  • 问题结果页——展示某个投票的结果。
  • 投票处理器——用于响应用户为某个问题的特定选项投票的操作。

编写更多视图

  1. 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)
    
  2. 将新视图添加进polls.urls模块

    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/34/vote/为例,Django会载入mysite.urls模块,寻找urlpatterns中的匹配项:

    # mysite/urls.py
    urlpatterns = [
        path('polls/', include('polls.urls')),
        path('admin/', admin.site.urls),
    ]
    

    找到匹配项polls/后,切掉匹配的文本(polls/),将剩余文本(34/vote/)发送至 polls.urls URLconf 做进一步处理。在polls.urls中,剩余文本匹配了<int:question_id>/vote/,使得Django调用views.py中的vote()

    vote(request=<HttpRequest object>, question_id=34)
    

    页面显示:

    Django处理一个请求的过程

写一个真正有用的视图

每个视图必须要做的只有两件事:返回一个包含被请求页面内容的HttpResponse对象,或者抛出一个异常,比如Http404。其他功能按需选择实现。

用index()函数实现功能:展示数据库中以发布日期排序的最近5个投票问题,以空格分割

# 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代码。

引入模板系统,只要创建一个视图,就可以将页面设计从代码中分离出来。

首先,在polls目录中创建一个templates目录,templates配置项默认设置了DjangoTemplates后端,Django会在这个目录中查找模板文件。

在templates目录下创建polls目录,再在该polls目录下新建一个html文件index.html,内容如下(教程只写出了核心代码,自己创建项目时最好使用完整的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视图来使用模板:

#polls/view.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]
    # 载入index.html文件
    template = loader.get_template('polls/index.html')
    # 向模板传递一个上下文(context),context将模板内的变量映射为Python对象
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))

显示无序问题列表:

关于模板命名空间:

虽然我们现在可以将模板文件直接放在 polls/templates 文件夹中(而不是再建立一个 polls 子文件夹),但是这样做不太好。Django 将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django 没有办法 区分 它们。我们需要帮助 Django 选择正确的模板,最好的方法就是把他们放入各自的 命名空间 中,也就是把这些模板放入一个和 自身 应用重名的子文件夹里。

快捷函数:render()

「载入模板,填充上下文,再返回由它生成的HttpResponse对象」的操作流程简化为快捷函数render()。

# polls/view.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)

使用render则index函数不再需要导入loader和HttpResponse,但是其他函数如detail需要保持HttpResponse导入。

render()函数的参数包括:

  1. request request 对象

  2. template_name 模板名称

  3. context 字典(可选)

将给定的模板和给定的上下文字典组合,并以渲染的文本返回一个HttpResponse对象。

抛出404错误

处理投票详情(detail)视图,当指定问题id对应的问题不存在时,抛出Http404异常。

注意:为保证代码运行,先创建detail.html模板,暂时输入{{ question }}

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

快捷函数: get_object_or_404()

尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程,可以使用快捷函数get_object_or_404

# polls/view.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})

使用模板系统

detail视图向模板传递了上下文变量question,在detail.html中添加:

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

模板指南

Django模板-菜鸟教程

变量被 {{}} 包围,从上下文(类似于字典的对象)中输出一个值。

点符号实现字典查找、属性查找和列表索引查找。

标签被 {%%} 包围,在渲染过程中提供了任意逻辑。

去除模板中的硬编码URL

硬编码:

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

使用{% url %}标签代替:

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

这个标签的工作方式是在 polls.urls 模块的 URL 定义中寻具有指定名字的条目:

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

polls.urls 模块修改详情视图的URL,如修改为 polls/specifics/12/

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

为URL名称添加命名空间

一个Django项目可能包含多个应用,在根URLconf中添加命名空间来区分:

# polls/urls.py
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'),
]

在index.html模板中,detail前要加上应用名称polls:

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

下一部分学习基础的表单处理和通用视图。

posted @ 2021-09-04 00:00  ikventure  阅读(86)  评论(0)    收藏  举报