Django-part3

视图

视图是Django应用程序中网页的一种“类型”,通常具有特定功能并具有特定模板。例如,在博客应用程序中,您可能具有以下视图:

  • 博客主页–显示最新的条目。
  • 条目“详细”页面–单个条目的永久链接页面。
  • 基于年份的存档页面–显示给定年份中所有条目的月份。
  • 基于月份的存档页面–显示所有月份以及给定月份中的条目。
  • 基于日期的存档页面–显示给定日期的所有条目。
  • 评论动作–处理对给定条目的发布评论。
    在我们的民意调查应用程序中,我们将具有以下四个视图:
  • 问题“索引”页面–显示最新的几个问题。
  • 问题“详细信息”页面–显示问题文本,没有结果,但有一个投票表。
  • 问题“结果”页面–显示特定问题的结果。
  • 投票行动–处理特定问题中特定选择的投票。
    在Django中,网页和其他内容是通过视图传递的。每个视图均由Python函数(或方法(对于基于类的视图而言))表示。Django将通过检查所请求的URL(准确地说,是域名之后的URL部分)来选择视图。为了从URL到视图,Django使用了所谓的“ URLconfs”。URLconf将URL模式映射到视图。

写更多的视图

让我们向添加更多视图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通过添加以下path()调用将这些新视图连接到模块中 :

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 /”。它将运行该detail()方法并显示您在URL中提供的任何ID。也尝试“ / polls / 34 / results /”和“ / polls / 34 / vote /” –这些将显示占位符结果和投票页面。

当有人从您的网站请求页面时,例如“ / polls / 34 /”,Django将加载mysite.urlsPython模块,因为该ROOT_URLCONF设置指向该模块 。它找到名为的变量urlpatterns并按顺序遍历模式。在找到匹配项之后'polls/',它将剥离匹配的文本("polls/"),并将其余文本–发送 "34/"到“ polls.urls” URLconf,以进行进一步处理。在那里匹配'/',从而导致对detail()视图的调用,如下所示:

detail(request=, question_id=34)

该question_id=34部分来自。使用尖括号“捕获” URL的一部分,并将其作为关键字参数发送给视图函数。:question_id>字符串的一部分定义了将用于标识匹配模式的名称,而该

.html除非需要,否则无需添加URL填充,在这种情况下,您可以执行以下操作:

path('polls/latest.html', views.index),

动作视图

每个视图负责执行以下两项操作之一:返回HttpResponse包含所请求页面内容的 对象,或者引发诸如之类的异常Http404。其余的取决于您。
您的视图是否可以从数据库中读取记录。它可以使用Django等模板系统,也可以不使用第三方Python模板系统。它可以使用所需的任何Python库生成PDF文件,输出XML,即时创建ZIP文件。
Django想要的只是那个HttpResponse。还是一个例外。
因为方便,所以让我们使用Django自己的数据库API,我们将在教程2中进行介绍。这是新index()视图中的一个选项,根据发布日期显示系统中最新的5个民意测验问题,以逗号分隔:

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)

但是,这里有一个问题:页面的设计在视图中硬编码。如果要更改页面的外观,则必须编辑此Python代码。因此,让我们使用Django的模板系统通过创建视图可以使用的模板来将设计与Python分开。
首先,在polls目录下创建一个新的templates目录,Django会在它里面查找模板文件。项目的 TEMPLATES配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates 后端,并将 APP_DIRS设置成了 True。这一选项将会让 DjangoTemplates 在每个 INSTALLED_APPS 文件夹中寻找 "templates" 子目录。这就是为什么尽管我们没有像在第二部分中那样修改 DIRS 设置,Django 也能正确找到 polls 的模板位置的原因。
在templates目录中,再创建一个新的子目录名叫polls,进入该子目录,创建一个新的html文件index.html。换句话说,你的模板文件应该是polls/templates/polls/index.html。因为 Django 会寻找到对应的app_directories ,所以你只需要使用polls/index.html就可以引用到这一模板了。

模板命名空间
你也许会想,为什么不把模板文件直接放在polls/templates目录下,而是费劲的再建个子目录polls呢?设想这么个情况,有另外一个app,它也有一个名叫index.html的文件,当Django在搜索模板时,有可能就找到它,然后退出搜索,这就命中了错误的目标,不是我们想要的结果。解决这个问题的最好办法就是在templates目录下再建立一个与app同名的子目录,将自己所属的模板都放到里面,从而达到独立命名空间的作用,不会再出现引用错误。
现在,将下列代码写入文件polls/templates/polls/index.html:

{% if latest_question_list %}
    
{% else %}
    

No polls are available.

{% endif %}

同时,修改视图文件polls/views.py,让新的index.html文件生效:

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对象之间的映射关系。
在浏览器中通过访问/polls/,你可以看到一个列表,包含“What’s up”的问卷,以及连接到其对应详细内容页面的链接点。
注意:如果你显示的是No polls are available.说明你前面没有添加Questions对象。前面的大量手动API操作你没有做。没关系,我们在admin中追加对象就可以。

快捷方式:render()
在实际运用中,加载模板、传递参数,返回HttpResponse对象是一整套再常用不过的操作了,为了节省力气,Django提供了一个快捷方式:render函数,一步到位!

修改成下面的代码:

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)

注意,我们不再需要导入 loader和 HttpResponse,而是从django.shortcuts导入了render。
render()函数的第一个位置参数是请求对象(就是view函数的第一个参数),第二个位置参数是模板。还可以有一个可选的第三参数,一个字典,包含需要传递给模板的数据。最后render函数返回一个经过字典数据渲染过的模板封装而成的HttpResponse对象。

现在让我们来编写返回具体问卷文本内容的视图:

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

就像render函数一样,Django同样为你提供了一个偷懒的方式,替代上面的多行代码,那就是get_object_or_404()方法,参考下面的代码:
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})

接下来看一下detail()的模板

{{ question.question_text }}

    {% for choice in question.choice_set.all %}
  • {{ choice.choice_text }}
  • {% endfor %}

删除模板中硬编码的URLs

在polls/index.html文件中,还有一部分硬编码存在,也就是href里的“/polls/”部分:

  • {{ question.question_text }}
  • 它对于代码修改非常不利。设想如果你在urls.py文件里修改了路由表达式,那么你所有的模板中对这个url的引用都需要修改,这是无法接受的!
    我们前面给urls定义了一个name别名,可以用它来解决这个问题。具体代码如下:

  • {{ question.question_text }}
  • Django会在polls.urls文件中查找name='detail'的url,具体的就是下面这行:

    path('/', views.detail, name='detail'),
    

    举个栗子,如果你想将polls的detail视图的URL更换为polls/specifics/12/,那么你不需要在模板中重新修改url地址了,仅仅只需要在polls/urls.py文件中,将对应的正则表达式改成下面这样的就行了,所有模板中对它的引用都会自动修改成新的链接:

    # 添加新的单词'specifics'
    path('specifics//', views.detail, name='detail'),
    

    URL names的命名空间

    本教程例子中,只有一个app也就是polls,但是在现实中很显然会有5个、10个、更多的app同时存在一个项目中。Django是如何区分这些app之间的URL name呢?
    答案是使用URLconf的命名空间。在polls/urls.py文件的开头部分,添加一个app_name的变量来指定该应用的命名空间:

    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'),
    ]
    
    一技破万法

    你可能感兴趣的:(Django-part3)