Django2.2丨视图和模板

概况

Django中的视图的概念是:一类具有相同功能和模板的网页的集合。

在Django中,网页和其他内容都是从视图派生而来。每一个视图表现为一个简单的Python函数(或是方法,如果是在基于类的视图里的话)。Django将会根据用户请求的URL来选择使用用哪个视图。

编写更多视图

在polls/views.py里添加更多视图。增加一些接受参数

# 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.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('/vote/', views.vote, name='vote'),
]

如果在浏览器中跳转到"/polls/34/",Django将会运行detail()方法并且展示在URL提供的问题ID。

当某人请求网站的某一页面时,例"polls/34/",Django将会载入mysite.urls模块,因为这个配置项ROOT_URLCONF中设置了。

然后Django寻找名为urlpatterns变量并且按序匹配正则表达式。找到匹配项"polls/",它切掉了匹配的文本(“polls/”),将剩余文本"34/",发送至"polls.urls",URLconf做进一步处理。

在剩余文本匹配了"int:question_id/",使得Django以如下形式调用detail()

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

question_id=34由int:question_id匹配生成。使用尖括号”捕获"这部分URL,且以关键字参数的形式发送给视图函数。

上述字符串的:question_id部分定义了将被用于区分匹配模式的变量名,而int:则是一个转换器决定了应该以什么变量类型匹配这部分的URL路径。

写一个有用的视图

每个视图必须要做的只有两件事

  • 返回一个包含请被请求页面内容的HttpResponse对象
  • 抛出一个异常,例Http404。

视图可以从数据库里读取记录,可以使用一个模板引擎,可以生成一个PDF文件,或者其他事情。

Django只要求返回的是一个HttpResponse,或者抛出一个异常。

在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

页面的设计写死在视图函数的代码里面。可以通过Django的模板系统创建一个视图,就可以将页面的设计从代码中分离出来。

在polls目录里创建一个templates目录,Django将会在这个目录里查找模板文件。

项目的TEMPLATES的配置描述了Django如何载入和渲染模板,默认的设置文件设置了DJangoTemplates后端,并将APP_DIRS设置成了True。这一选项将会让DjangoTemplates在每个INSTALLED_APPS文件夹中寻找"templates"子目录。

在templates目录里,创建一个目录polls,然后再其中新键一个index.html。此时的模板文件的路径是polls/templates/polls/index.html。因为Django会寻找到对应的app_directories,所以只需要使用polls/index.html就可以引用这一模板

  • 模板命名空间

虽然可以将模板文件直接放在polls/templates文件加中(而不是再创建一个polls子文件夹),因为Django会选择第一个匹配的模板文件,如果由一个模板文件和另一个应用中的某个模板文件重名,Django没有办法区分它们。

所以最简单的办法就i是把它们放入各自的命名空间中,也就是把这些模板放入一个和自身应用重名的子文件夹里。

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

更新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)。这个上下文是一个字典,它将模板内的变量映射为Python对象。

快捷函数:render()

载入模块,填充上下文,再返回由它生成的HttpResponse对象是一个非常常用的操作流程。

Django提供了一个快捷函数

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

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

如果指定问题ID所对应的问题不存在,这个视图就会抛出一个Http404异常。

快捷函数:get_object_or_404()

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

Django也提供了一个快捷函数

# 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_list_or_404()函数,工作原理和get_object_or_404()一样。如果列表为空则抛出Htto404异常。

使用模板系统

查看detail()视图,它向模板传递了上下文变量qeustion

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

模板系统统一使用点符号来访问变量的属性。

在实例{{ question.question_text }}中,首先Django尝试对question对象使用字典查找(也就是使用obj.get(str)操作),如果失败了就尝试属性查找(也就是obj.str操作),如果这一操作也失败了,将会尝试列表查找(也就是obj[int]操作)

question.chaoice_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 %}标签代替它。

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

在模板中的使用

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

如果想改变投票详情视图的URL,例polls/specifics/12/,就不需要再模板里修改任何东西,只要再urls.py里修改就可以

...
# added the word 'specifics'
path('specifics//', views.detail, name='detail'),
...

为URL名称添加命名空间

目前只有一个应用,polls。如果应用增加到10个、20个或者更多。Django可以通过添加命名空间来防止无法分辨重名的URL。

# polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    path('/', views.detail, name='detail'),
    path('/results/', views.results, name='results'),
    path('/vote/', views.vote, name='vote'),
]

原polls/index.html

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

重新编辑的polls/index.html

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

你可能感兴趣的:(django)