第6有个别传送门,普通话文档

迎接大家访问笔者的民用网站《刘江先生的博客和科目》:www.liujiangblog.com

曾经联手到gitbook,想阅读的请转到gitbook: Django 1.10
汉语文书档案

重点分享Python 及Django教程以及有关的博客


首先片段传送门

其三有个别传送门

第陆有的传送门

3.2 模型和数据库Models and
databases

3.2.2 查询操作making
queries

3.3.8
会话sessions

Writing your first Django app, part 4This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on simple form processing and cutting down our code.紧接着Tutorial 3,大家延续支付这么些投票的web应用,本章将关怀简单的表单处理和代码优化#### Write a simple form#### 编纂多个大约的表单Let’s update our poll detail template (“polls/detail.html”) from the last tutorial, so that the template contains an HTML <form> element:让我们立异一下在上三个课程中编辑的投票详细页面包车型客车模版(“polls/detail.html”),让它涵盖一个HTML<form> 成分:polls/templates/polls/detail.html<h1>{{ question.question_text }}</h1>{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}<form action="{% url 'polls:vote' question.id %}" method="post">{% csrf_token %}{% for choice in question.choice_set.all %}<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /><label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />{% endfor %}<input type="submit" value="Vote" /></form>A quick rundown:简要表达:+ The above template displays a radio button for each question choice. The value of each radio button is the associated question choice’s ID. The name of each radio button is “choice”. That means, when somebody selects one of the radio buttons and submits the form, it’ll send the POST data choice=# where # is the ID of the selected choice. This is the basic concept of HTML forms.+ 在detail网页模板中,大家为Question对应的各个Choice都添加了3个单选按钮用于选用。各类单选按钮的value属性是相应的一一Choice的ID。种种单选按钮的name是”choice”。那代表,当有人精选二个单选按钮并付诸表单时,它将发送三个POST数据choice=#,其中# 为采取的Choice的ID。那是HTML 表单的基本概念。+ We set the form’s action to {% raw %}{% url ‘polls:vote’ question.id %}{% raw %}, and we set method=”post”. Using method=”post” (as opposed to method=”get”) is very important, because the act of submitting this form will alter data server-side. Whenever you create a form that alters data server-side, use method=”post”. This tip isn’t specific to Django; it’s just good Web development practice.+ 大家设置表单的action为{% raw %}{% url ‘polls:vote’ question.id %}{% raw %},并安装 method=”post”。使用method=”post”(与其相对的是method=”get”)是那叁个主要的,因为这么些提交表单的一颦一笑会变动服务器端的数量。 无论何时,当您须要创造三个变更服务器端数据的表单时,请使用 method=”post”。那不是Django的一定技巧;那是一举两得的网站开发执行。+ forloop.counter indicates how many times the {% raw %}for{% endraw %} tag has gone through its loop+ forloop.counter 表示{% raw %}for{% endraw %} 标签已经循环的次数+ Since we’re creating a POST form (which can have the effect of modifying data), we need to worry about 克罗斯 Site Request Forgeries. Thankfully, you don’t have to worry too hard, because Django comes with a very easy-to-use system for protecting against it. In short, all POST forms that are targeted at internal U奥迪Q3Ls should use the {% raw %}{%csrf_token %} {% endraw %}template tag.+ 由于大家制造的是贰个POST表单(会转移服务器端的多寡),那大家就会担心跨站伪造请求的抨击。但幸而的是,大家不须要太担心,因为Django自带了几个简约易用的种类来防御。一句话来说,全数提交到对象U奥迪Q5Ls的POST表单,都应当安装{% raw %}{%csrf_token %} {% endraw %}模板标签Now, let’s create a Django view that handles the submitted data and does something with it. Remember, in Tutorial 3, we created a U中华VLconf for the polls application that includes this line:今后,让我们来创建贰个Django视图来处理提交的多少。 记住,在教程 3中,大家为投票应用创造了七个U大切诺基Lconf ,蕴涵这一行:polls/urls.pyurl(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),We also created a dummy implementation of the vote() function. Let’s create a real version. Add the following to polls/views.py:大家也开创了贰个不要紧实际功效的vote()函数。今后让我们来的确。将下边代码添加到polls/views.py:polls/views.pyfrom django.shortcuts import get_object_or_404, renderfrom django.http import HttpResponseRedirect, HttpResponsefrom django.urls import reversefrom .models import Choice, Question# ...def vote(request, question_id):question = get_object_or_404(Question, pk=question_id)try:selected_choice = question.choice_set.get(pk=request.POST['choice'])except (KeyError, Choice.DoesNotExist):# Redisplay the question voting form.return render(request, 'polls/detail.html', {'question': question,'error_message': "You didn't select a choice.",})else:selected_choice.votes += 1selected_choice.save()# Always return an HttpResponseRedirect after successfully dealing# with POST data. This prevents data from being posted twice if a# user hits the Back button.return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))This code includes a few things we haven’t covered yet in this tutorial:那段代码有局地大家未在科目提及的学识:+ request.POST is a dictionary-like object that lets you access submitted data by key name. In this case,request.POST[‘choice’] returns the ID of the selected choice, as a string. request.POST values are always strings.request.POST 是三个近乎字典的靶子,让你能够透过重点字的名字获取提交的数额。这么些事例中,request.POST[‘choice’] 以字符串情势重回选择的Choice的ID。request.POST 的值永远是字符串Note that Django also provides request.GET for accessing GET data in the same way – but we’re explicitly using request.POST in our code, to ensure that data is only altered via a POST call.同样的,Django也提供了request.GET办法来收获GET数据,但大家在代码中明显地利用request.POST,以保险数据只可以通过POST调用改动。request.POST[‘choice’] will raise KeyError if choice wasn’t provided in POST data. The above code checks for KeyError and redisplays the question form with an error message if choice isn’t given.要是POST数据没有choice,request.POST[‘choice’] 会抛出 KeyError非凡。上边的代码会检查 KeyError,假如没有对应的choice,将会再度展现question表单和2个错误音讯。After incrementing the choice count, the code returns an HttpResponseRedirect rather than a normal HttpResponse. HttpResponseRedirect takes a single argument: the URubiconL to which the user will be redirected (see the following point for how we construct the UTiguanL in this case).在加码choice的票数之后,代码重回2个HttpResponseRedirect而不是HttpResponseHttpResponseRedirect 只接收二个参数:用户将被重定向的URL(上边请看大家怎么样组织这么些U中华VL)As the Python comment above points out, you should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isn’t specific to Django; it’s just good Web development practice.正如上面的Python注释建议的,你应该在成功拍卖POST数据后延续回到三个HttpResponseRedirect。 那不是Django的一定技巧; 那是那多少个美好网站在开发实践中形成的共同的认识。We are using the reverse() function in the HttpResponseRedirect constructor in this example. This function helps avoid having to hardcode a URL in the view function. It is given the name of the view that we want to pass control to and the variable portion of the URL pattern that points to that view. In this case, using the URLconf we set up in Tutorial 3, this reverse() call will return a string like:'/polls/3/results/'在这些例子中,大家用 reverse() 函数作为 HttpResponseRedirect的参数,那么些函数制止了笔者们在视图函数中硬编码ULANDL。它供给大家提交大家想要跳转的视图的名字和该视图所对应的UHavalL情势中须求给该视图提供的参数。 在本例中,使用在教程3中设定的UCR-VLconf,调用 reverse() 将回来三个这么的字符串:'/polls/3/results/'where the 3 is the value of question.id. This redirected U酷威L will then call the ‘results’ view to display the final page.3正是 question.id的值。重定向的U奥迪Q7L将调用’results’ 视图来体现最后的页面。As mentioned in Tutorial 3, request is an HttpRequest object. For more on HttpRequest objects, see the request and response documentation.正如教程3提到的,request是一个HttpRequest目的,越多关于HttpRequest指标的内容,请看request and response documentation.After somebody votes in a question, the vote() view redirects to the results page for the question. Let’s write that view:当有人对Question进行投票后,vote()视图将呼吁重定向到Question的结果界面。让大家来编排那么些视图:polls/views.pyfrom django.shortcuts import get_object_or_404, renderdef results(request, question_id):question = get_object_or_404(Question, pk=question_id)return render(request, 'polls/results.html', {'question': question})This is almost exactly the same as the detail() view from Tutorial 3. The only difference is the template name. We’ll fix this redundancy later.Now, create a polls/results.html template:那大致和教程3中的detail()视图一模一样,大家将在稍后消除这么些冗余难题。以往,大家成立 polls/results.html 模板:polls/templates/polls/results.html<h1>{{ question.question_text }}</h1><ul>{% for choice in question.choice_set.all %}<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>{% endfor %}</ul><a href="{% url 'polls:detail' question.id %}">Vote again?</a>Now, go to /polls/1/ in your browser and vote in the question. You should see a results page that gets updated each time you vote. If you submit the form without having chosen a choice, you should see the error message.> Note> The code for our vote() view does have a small problem. It first gets the selected_choice object from the database, then computes the new value of votes, and then saves it back to the database. If two users of your website try to vote at exactly the same time, this might go wrong: The same value, let’s say 42, will be retrieved for votes. Then, for both users the new value of 43 is computed and saved, but 44 would be the expected value.> This is called a race condition. If you are interested, you can read Avoiding race conditions using F()to learn how you can solve this issue.> 注意> vote()视图函数的代码或许会有标题。首先它从数据库取出所选的choice对象,然后总计votes的新颖值,然后保留到数据库。假诺你的网站有五个用户在同方今间投票,那就会出错了:同样的值,比如说42,将被votes同时取获得,然后,对两个用户来说最后总括的值都以43,并保留了,不过实际上应该是44.> 那称之为竞态条件。借使您有趣味,你能够阅读Avoiding race conditions using F()学学怎么着消除那几个标题。#### Use generic views: Less code is better#### 行使普通view:代码照旧少点好The detail() (from Tutorial 3) and results() views are very simple – and, as mentioned above, redundant. The index() view, which displays a list of polls, is similar.教程3detail()视图和results()都卓殊简单——并且,如下面所说,代码比较体面。展现投票列表的index()视图也和她俩好像。These views represent a common case of basic Web development: getting data from the database according to a parameter passed in the U卡宴L, loading a template and returning the rendered template. Because this is so common, Django provides a shortcut, called the “generic views” system.这一个视图反映基本的Web开发中的三个广泛情状:遵照ULacrosseL中的参数从数据库中获取数据、载入模板文件然后回来渲染后的沙盘。 由于这种情状十三分广阔,Django提供了一种名叫“generic views”的系统能够方便地拓展处理。Generic views abstract common patterns to the point where you don’t even need to write Python code to write an app.Generic views会将普遍的方式抽象化,能够使你在编写app时居然不须要编写制定Python代码。Let’s convert our poll app to use the generic views system, so we can delete a bunch of our own code. We’ll just have to take a few steps to make the conversion. We will:1. Convert the UHavalLconf.2. Delete some of the old, unneeded views.3.Introduce new views based on Django’s generic views.Read on for details.让我们将大家的投票应用转换成使用通用视图系统,那样大家得以去除许多大家的代码。大家唯有需求做以下几步来形成更换: 我们将:1. 转换UOdysseyLconf2. 删减一些旧的、不再需求的代码。3. 引进基于Django通用视图的新视图。请继续读书来打探详细新闻。> Why the code-shuffle?> Generally, when writing a Django app, you’ll evaluate whether generic views are a good fit for your problem, and you’ll use them from the beginning, rather than refactoring your code halfway through. But this tutorial intentionally has focused on writing the views “the hard way” until now, to focus on core concepts.> You should know basic math before you start using a calculator.> 为啥重构代码> 一般的话,当编辑3个Django应用时,你应超越评估一下通用视图是不是能够缓解你的难题,你应有在一从头选择它,而不是进展到四分之二时重构代码。本学科近日结束是明知故问将重要放在以“艰辛的不二法门”编写视图,那是为将第①放在宗旨概念上。> 就像是在应用总结器从前您须要掌握基本的数学一样。#### Amend URLconf#### 改良的URLconfFirst, open the polls/urls.py ULacrosseLconf and change it like so:首先,编辑 polls/urls.py U汉兰达Lconf,修改成如下:polls/urls.pyfrom django.conf.urls import urlfrom . import viewsapp_name = 'polls'urlpatterns = [url(r'^$', views.IndexView.as_view(), name='index'),url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),]Note that the name of the matched pattern in the regexes of the second and third patterns has changed from <question_id> to <pk>.注意在第3个和第五个情势的正则表明式中,匹配的方式的名字由<question_id> 变成 <pk>。#### Amend views#### 改良的viewNext, we’re going to remove our old index, detail, and results views and use Django’s generic views instead. To do so, open the polls/views.py file and change it like so:接下去咱们将去除老的index, detail, and results 视图,并替换为Django的通用视图。要落成那么些,请打开 polls/views.py,按如下修改:polls/views.pyfrom django.shortcuts import get_object_or_404, renderfrom django.http import HttpResponseRedirectfrom django.urls import reversefrom django.views import genericfrom .models import Choice, Questionclass IndexView(generic.ListView):template_name = 'polls/index.html'context_object_name = 'latest_question_list'def get_queryset(self):"""Return the last five published questions."""return Question.objects.order_by('-pub_date')[:5]class DetailView(generic.DetailView):model = Questiontemplate_name = 'polls/detail.html'class ResultsView(generic.DetailView):model = Questiontemplate_name = 'polls/results.html'def vote(request, question_id):... # same as above, no changes needed.We’re using two generic views here: ListView and DetailView. Respectively, those two views abstract the concepts of “display a list of objects” and “display a detail page for a particular type of object.”那里我们用了多个通用视图: ListViewDetailView。那四个视图分别抽象“呈现叁个指标列表”和“呈现1个一定项目对象的详细音信页面”那二种概念。+ Each generic view needs to know what model it will be acting upon. This is provided using the model attribute.+ 每一种通用视图必要了然它将功用于哪个模型。 那由model 属性提供。+ The DetailView generic view expects the primary key value captured from the URL to be called “pk”, so we’ve changed question_id to pk for the generic views.DetailView企望从UPAJEROL中抓获名为”pk”的主键值,因而大家把polls/urls.py中question_id改成了pk以使通用视图能够找到主键值 。By default, the DetailView generic view uses a template called <app name>/<model name>_detail.html. In our case, it would use the template “polls/question_detail.html”. The template_name attribute is used to tell Django to use a specific template name instead of the autogenerated default template name. We also specify the template_name for the results list view – this ensures that the results view and the detail view have a different appearance when rendered, even though they’re both a DetailView behind the scenes.暗中同意情形下,通用视图 DetailView 使用3个称为<app name>/<model name>_detail.html的沙盘。在大家的例证中,它是 “polls/question_detail.html”模板。template_name属性是用来告诉Django使用三个钦赐的模板名字,而不是自动生成的默许名字。 大家也为results列表视图内定了template_name —— 那确定保障results视图和detail视图在渲染时享有分歧的外观,固然它们在后台都以同贰个 DetailView 。Similarly, the ListView generic view uses a default template called <app name>/<model name>_list.html; we use template_name to tell ListView to use our existing “polls/index.html” template.类似地,ListView 使用1个名为<app name>/<model name>_list.html的私下认可模板;大家利用template_name 来告诉ListView 使用大家团结的”polls/index.html”模板。In previous parts of the tutorial, the templates have been provided with a context that contains the question and latest_question_list context variables. For DetailView the question variable is provided automatically – since we’re using a Django model (Question), Django is able to determine an appropriate name for the context variable. However, for ListView, the automatically generated context variable is question_list. To override this we provide the context_object_name attribute, specifying that we want to use latest_question_list instead. As an alternative approach, you could change your templates to match the new default context variables – but it’s a lot easier to just tell Django to use the variable you want.在后边的科目中,提供模板文件时都带有1个带有question 和 latest_question_list 变量的context。对于DetailView ,question变量会自行提供—— 因为我们选择Django 的模子 (Question), Django 可以为context 变量支配三个相宜的名字。然则对于ListView, 自动生成的context 变量是question_list。为了掩盖这一个作为,大家提供 context_object_name 属性,表示大家想选用latest_question_list。作为一种替换方案,你能够变动你的模版来同盟新的context变量 —— 但直接报告Django使用你想要的变量会便利很多。Run the server, and use your new polling app based on generic views.运行服务器,使用一下基于通用视图的新投票应用。For full details on generic views, see the generic views documentation.越多关于通用视图的详细消息,请查看 通用视图像和文字书档案.When you’re comfortable with forms and generic views, read part 5 of this tutorial to learn about testing our polls app.当你熟习了表单和通用视图,请看教程5上学怎样测试大家的投票应用

目录

2.5 第③个Django app,Part 3:视图和模板

  • 2.5.1 概览
  • 2.5.2 编写越多的视图
  • 2.5.3 编写能实际干点活的视图
  • 2.5.4 404错误
  • 2.5.5 使用模板系统
  • 2.5.6 删除模板中硬编码的U奥迪Q5Ls
  • 2.5.7 U中华VL names的命名空间

2.6 第三个DJango app,Part 4:表单和泛型视图

  • 2.6.1 编写1个简便的form
  • 2.6.2 使用泛型视图:收缩代码冗余

2.5 第一个Django app,Part 3:视图和模板

本章承上启下,首要介绍Django的视图概念。

2.5.1 概览

一个视图就是3个网页“类型”,常常提供特定的效益或特定的模板。例如:在一个博客应用中,你只怕会看出下列视图:

  • 博客主页:显示最新发表的有个别剧情
  • 条目详细页面:每个条目对应的恒久页面
  • 依照年的篇章页面:彰显钦定年内的装有博客文章
  • 依照月的篇章页面:展现内定月内的保有博客小说
  • 依据天的篇章页面:展现钦定日内的富有博客小说
  • 揭橥评论:处理针对某篇博客发表的评价

在大家的投票应用中,大家将确立上面包车型客车视图:

  • 问卷“index”页:突显最新的一部分问卷
  • 问卷“detail”页面:呈现2个问卷的详尽文本内容,没有调查结果不过有三个投票或考察表单。
  • 问卷“results”页面:呈现有些问卷的投票或调查结果。
  • 投票动作页面:处理针对有个别问卷的有个别选项的投票动作。

在Django中,网页和其他的一部分剧情都是经过视图来散发的。视图呈现为多个简练的Python函数(在依照类的视图中称之为方法)。Django通过相比请求的U君越L地址来采用相应的视图。

在您平时的网页上,你或然时时会遇见类似“ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199Corolla2D9B65B1B”的url。庆幸的是Django帮忙使用越发简介的U途锐L格局,而不须求编写制定上面这种复杂的url。

二个U宝马X3L形式其实正是三个U昂科拉L通用表明式,例如:/newsarchive///。为了使得UHavalL形式映射到对应的视图,DJango使用U中华VLconfs来成功这一办事。本学科介绍宗旨的U奥德赛Lconfs使用格局,更多的内容,请参考6.23节。

2.5.2 编写越来越多的视图

上面,让我们开辟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.py文件中加入上面包车型大巴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/”(注意:那里大致了域名。其余,使用了二级路由,url中都要添加polls部分,参考前边的章节),它将运转detail()方法,然后在页面中呈现你在url里提供的ID。访问“/polls/34/results/”和“/polls/34/vote/”,将分别展现预约义的伪结果和投票页面。

地点访问的路由进度如下:当有人访问“/polls/34/”地址时,Django将首先加载mysite.urls模块,因为它是settings文件里设置的根U奥迪Q3L配置文件。在该文件里,Django发现了urlpatterns变量,于是在其内按梯次的进展匹配。当它相当上了^polls/,就脱去url中匹配的文本polls/,然后将盈余的文书“34/”,传递给“polls.urls”实行下一步的处理。在polls.urls,又特出到了r’^(?P<question_id>[0-9]+)/$’,最后结果正是调用该方式对应的detail()视图,也便是底下的函数:

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

函数中的question_id=’34’参数,是由(?P[0-9]+)而来。在正则表明式中经过两个双圆括号,Django会捕获它格外到的值并传递给相应的视图,作为视图的职分参数之一,而?P则表示笔者要给这些捕获的值内定一个特种的变量名,在视图中能够透过question_id那个变量名随意的引用它,形成三个要害字参数,不用考虑参数的职责。至于[0-9]+则是3个很简单的原生正则表明式,用于匹配一种类一连的数字,它格外到的值也等于具体要传递的参数值。

有着的U奥迪Q3L格局都以正则表明式,Django不限制你在url格局中的书写形式。可是,你真正没要求书写八个之类的较为愚昧的蕴藏”.html”的方式,它鲜明是没须要,不够精炼的:

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

您一点一滴能够用下边包车型地铁情势代表下边包车型地铁:

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

2.5.3 编写能实际干点活的视图

眼下大家说过,每种视图至少做两件事之一:重回1个包含呼吁页面包车型客车HttpResponse对象大概弹出三个接近Http404的10分。此外的则随你便,你爱干嘛干嘛。

你的视图可以从数据库读取记录,恐怕不读。你能够选用Django提供的模板系统恐怕第贰方的Python模板系统,可能干脆啥也不用。你能够生成PDF文件、输出XML,创建ZIP压缩文件,任何你想做的事,使用任意你想用的Python库。

而Django想要的唯有HttpResponse可能多个极度。

因为如此很便捷,接下去让我们选拔DJango自个儿的数据库API,大家在上边的学Corey介绍过的。上边是二个新的index()视图,它会基于通知日期显示近日的多少个投票问卷,通过逗号分隔。

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)

# 下面是那些没改动过的视图(detail, results, vote)

只是此地依然有个难题:在视图中的页面时硬编码的。假诺您想更改页面包车型大巴显得,就亟须修改那里的Python代码。因而,让大家来选取Django提供的模版系统,解耦视图和模板之间的联络。

先是,在polls目录下开创二个新的templates目录,Django会在它个中查找模板文件。

此地解释一下:Django项目标settings配置文件中定义了什么样加载和渲染模板。暗许的设置
是DjangoTemplates后端,并且APP_DI昂科威S参数被设置为True。作为惯例,Django也会寻找各种在INSTALLED_APPS配置项里注册过的app本人目录下的templates子目录。

重回你刚才创立的templates目录中,更创制1个新的子目录名叫polls,进入该子目录,创设五个新的html文件index.html。换句话说,你的沙盘文件应当是polls/templates/polls/index.html。依据地点的诠释,你未来能够在DJango中央直机关接使用polls/index.html引用该公文了。

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

现在,将下列代码写入文件:
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.html文件生效:
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文件,并传递给它2个参数,那个参数是几个字典,包涵了模版变量名和python对象时期的投射关系。

在浏览器中经过走访“/polls/”,你能够看看多少个列表,包罗“What’s
up”的问卷,以及一连到其对应详细内容页面包车型地铁链接点。

火速方式:render()

在实际应用中,加载模板、传递参数,重临HttpResponse对象是一整套再常用但是的操作了,为了节省力气,Django提供了2个快速情势: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)

render()函数的首先个地点参数是呼吁对象(正是view函数的率先个参数),第一个任务参数是模板,还足以有二个可选的第3参数—三个字典,包括需求传递给模板的多少。最后render函数重临3个经过字典数据渲染过的模版封装而成的HttpResponse对象。

2.5.4 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荒谬。

稍后大家会谈谈你应有在polls/detail.html里面写点什么代码,不过今后您能够省略的先写这么个东西,用来彰显方面的404张冠李戴:

polls/templates/polls/detail.html

{{ question }}

飞速格局: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})

别说小编没提示你,和render一样,也急需在Django内置的火速格局模块中程导弹入get_object_or_404()!

get_object_or_404()函数将多少个Django模型作为第①个职责参数,后边能够跟上任意个数的最首要字参数(python函数参数的归类和语法一定要搞明白了!这个首要字参数是传递给模型管理器的get()函数的,在前边会讲到。),假若指标不存在则弹出Http404荒谬。

理念:
为什么要费劲的使用一个get_object_or_404()快捷方式,而不是让系统自动的捕获ObjectDoesNotExist异常或者弹出模型API的Http404异常?仅仅只是为了少写点代码?
因为后两者会耦合模型层和视图层。Django的一个非常重要的设计目标是维持各层级之间的松耦合。更多的内容请参考3.3.5节。

平等,那里还有一个get_list_or_404()函数,和方面的get_object_or_404()类似,只然则是用来代表filter()函数,当查问列表为空时弹出404谬误。(filter是模型API中用来过滤查询结果的函数,它的结果是二个列表集。而get则是询问3个结果的措施,和filter是1个和三个的界别!)

2.5.5 使用模板系统

再次来到detail()视图。将上下文变量question传递给相应的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>

后面大家说过了,在模板系统中圆点“.”是智勇双全的魔术师,你能够用它访问对象的特性。在例子{{
question.question_text
}}中,DJango首先会在question对象中尝试寻找二个字典,倘使失败,则尝试寻找属性,如若再失利,则尝试作为列表的目录举行查询。

在 {% for %}
循环中的方法调用——poll.choice_set.all其实就是Python的代码poll.choice_set.all(),它将回来一组可迭代的
Choice 对象,并用在 {% for %} 标签中。

越多内容请查看3.5节的沙盘向导!

2.5.6 删除模板中硬编码的UQX56Ls

在polls/index.html文件中,还有局地硬编码存在,也便是herf里的“/polls/”部分:

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

个中的紧耦合对于代码修改12分不利于。
但是,大家前边给urls定义了一个name别称,能够用它来替代。具体代码如下:

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

Django会在polls.urls文件中追寻name=’detail’的url,具体的正是上边这行:

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

举个栗子,借使您想将polls的detail视图的U冠道L更换为polls/specifics/12/,那么你不必要在模板中重复修改url地址了,仅仅只供给在polls/urls.py文件中,将相应的正则表明式改成上面那样的就行了:

# 添加新的单词'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

2.5.7 URAV4L names的命名空间

本学科例子中,唯有叁个app也正是polls,但是在具体中很鲜明会有四个、13个、越多的app同时设有三个类型中。Django是什么样区分那么些app之间的U景逸SUVL
name呢?

答案是使用U本田UR-VLconf的命名空间。在polls/urls.py文件的起先部分,添加1个app_name的变量来钦定该行使的命名空间:

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/templates/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>

留意引用方法是引号而不是圆点也不是斜杠!!!!!!!!!!!!

到此,我们得以进去下有个别的课程了。

2.6 第1个DJango app,Part 4:表单和泛型视图

本有的器重介绍form表单相关。

2.6.1 编写三个简约的form

以往在我们原先的polls/detail.html文件中添加一个表单成分:

polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>

差不离表明:

  • 地点的模板展现一多元单选按钮,按钮的值是选拔的ID,按钮的名字是字符串”choice”。这表示,当您挑选了个中某些按钮,并提交表单,五个带有数据choice=#的POST请求将被发送到钦赐的url,#是被挑选的挑三拣四的ID。那正是HTML表单的基本概念。
  • 假如您有一定的前端开发基础,那么form标签的action属性和method属性你应该很明白它们的意思,action表示您要发送的目标url,method表示提交数据的办法,一般分POST和GET,越多的分解就不是本教程干的工作了,你供给补课。
  • forloop.counter是DJango模板系统一管理理专门提供的二个变量,用来代表您近期循环的次数,一般用来给循环项目增进有序数标。
  • 是因为大家发送了一个POST请求,就必须考虑2个跨站请求伪造的难题,简称CS安德拉F(具体意思请百度)。Django为你提供了一个简易的艺术来制止那几个苦恼,那就是在form表单内添加一条{%
    csrf_token
    %}标签,标签名不可更改,固定格式,地方任意,只假诺在form表单内。然则(译者注),那几个格局对form表单的交给情势有利好使,可是纵然是用ajax的措施交给数据,那么就很费劲了。个人认为不及直接在Django配置中关闭那些看似有成效,其实然并卵的CSOdysseyF得了。

当今,让我们成立多个拍卖提交过来的多寡的视图。前边大家曾经写了贰个“占坑”的vote视图的url:
polls/urls.py

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

以及“占坑”的vote视图函数,我们把坑填起来:
polls/views.py

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from .models import Choice, Question
# ...

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # 发生choice未找到异常时,重新返回表单页面,并给出提示信息
        return render(request, 'polls/detail.html', {
        'question': question,
        'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # 成功处理数据后,自动跳转到结果页面,防止用户连续多次提交。
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

稍加新的东西,大家要解释一下:

  • request.POST是1个近似字典的指标,允许你通过键名访问提交的数目。本例中,request.POST[’choice’]再次来到被选取选项的ID,并且值的体系永远是string字符串,那怕它看起来像数字,记住了!!!!同样的,你也可以用接近的手腕获得GET请求发送过来的数码,三个道理。
  • request.POST[’choice’]有可能接触贰个KeyError很是,假若您的POST数据里不曾提供choice键值,在那种意况下,下面的代码会回去表单页面并交给错误提醒。译者注:平日我们会给个暗许值,幸免这种格外的发生,例如:request.POST[’choice’,None],1个None消除全体有失水准态。
  • 在甄选计数器加一后,再次回到的是一个HttpResponseRedirect而不是先前大家常用的HttpResponse。HttpResponseRedirect要求1个参数:重定向的URAV4L。那里有一个提出,当您成功拍卖POST数据后,应当保持2个出色的习惯,始终再次回到贰个HttpResponseRedirect。那不仅仅是对Django而言,它是八个优秀的WEB开发习惯。
  • 我们在上头HttpResponseRedirect的构造器中应用了叁个reverse()函数。它能匡助大家幸免在视图函数中硬编码UKugaL。它首先供给二个大家在UCRUISERLconf中内定的name,然后是传递的数目。例如’/polls/3/results/’,个中的3是某些question.id的值。重定向后将进入’polls:results’对应的视图,并将question.id传递给它。白话来讲,正是把活扔给此外二个路由对应的视图去干。

当有人对有些难题投票后,vote()视图重定向到了问卷的结果展现页面。上边大家来写这些处理结果页面包车型地铁视图:
polls/views.py

from django.shortcuts import get_object_or_404, render

def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})

一律,还索要写个模板。(译者注:路由、视图、模板、模型!你要求的套路….)

polls/templates/polls/results.html

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

最近您能够取浏览器中走访/polls/1/了,投票吧。你会看到七个结出页面,每投贰回,它的内容就立异一遍。假诺你提交的时候没有选用品种,则会获取一个张冠李戴提醒。

注释:(怎么这么多注释....)
在上面的vote视图中的代码存在一点小问题。如果有2个用户同时在对某项进行提交时,很有可能发生同时对数据库进行读写的情况,它有可能导致数据的不协调,也就是所谓的“竞态”,如果你感兴趣,可以参考6.15节相关的通过使用F()查询来避免竞态的讨论和介绍。

2.6.2 使用泛型视图:减少代码冗余

上边的detail、index和results视图的代码万分相像,有点冗余,那是三个程序猿不能够经受的。他们都抱有类似的业务逻辑,实现类似的作用:通过从UXC90L传递过来的参数去数据库查询数据,加载三个模板,利用刚才的多寡渲染模板,重临那些模板。由于那个进程是这么的科学普及,Django又很通情达理的帮你想办法偷懒了,它提供了一种急速格局,名为“泛型视图”系统。

于今,让大家来试试看将本来的代码改为利用泛型视图的法门,整个经过分三步走:

  • 改变URLconf
  • 除去一些旧的不算的视图
  • 应用基于泛型视图的新视图

注释:Django官方的“辩解”
缘何本学科的代码来回改动这么频仍?
答:平日在写贰个Django的app时,大家一初步就要控制是使用泛型视图依然不要,而不是等到代码写到3/6了才重构你的代码成泛型视图。可是本课程为了让您清晰的通晓视图的内蕴,“故意”走了一条比较2的路,因为大家的历史学是:在你使用总括器此前您得先知道基本的数学公式。

修改URLconf

开拓polls/urls.py文件,将其修改成下边包车型大巴楷模:

from django.conf.urls import url
from . import views

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

请小心:在地方的的第三,3条款少校原本的<question_id>修改成了<pk>.

修改视图

接下去,打开polls/views.py文件,删掉index、detail和results视图,替换来Django的泛型视图,如下所示:

polls/views.py

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Choice, Question


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'
    def get_queryset(self):
    """返回最近发布的5个问卷."""
        return Question.objects.order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'


class ResultsView(generic.DetailView):
    model = Question
    template_name ='polls/results.html'


def vote(request, question_id):
... # 这个视图未改变!!!

在此处,我们应用了二种泛型视图:ListView和DetailView(译者注:它们是当做父类被一而再的)。那两边分别表示“显示1个对象的列表”和“突显特定项目对象的事无巨细页面”的抽象概念。

  • 每一个泛型视图都亟待知道它要效益在哪些模型上,那通过model属性提供。

  • DetailView泛型视图需求从URL捕获到的称为”pk”的主键值,因而大家在url文件军长2和3条目标<question_id>修改成了<pk>

暗中同意意况下,DetailView泛型视图使用2个名叫<app name>/<model name>_detail.html的模板。在本例中,实际选用的是”polls/question_detail.html”。template_name属性就是用来内定那一个模板名的,用于代替自动生成的暗许模板名。(译者注:一定要过细观望地点的代码,对号落座,注意细节。)同样的,在resutls列表视图中,为了钦命template_name为’polls/results.html’,那样就保险了纵然resulst视图和detail视图同样一连了DetailView类,使用了一样的model:Qeustion,但它们照旧会显得分歧的页面。(译者注:模板分化嘛!so
easy!)

好像的,ListView泛型视图使用2个私下认可模板称为<app name>/<model name>_list.html。大家也采纳template_name那些变量来告诉ListView使用我们早已存在的
“polls/index.html”模板,而不是使用它自个儿暗中同意的老大。

在课程的前方部分,大家给模板提供了三个蕴涵question和latest_question_list的上下文变量。而对此DetailView,question变量会被电动提供,因为大家利用了Django的模型(Question),Django会智能的挑选适宜的上下文变量。不过,对于ListView,自动生成的上下文变量是question_list。为了掩盖它,我们提供了context_object_name属性,钦命说大家愿意利用latest_question_list而不是question_list。

今后你能够运行开发服务器,然后试试基于泛型视图的应用程序了。
翻看越来越多关于泛型视图的剧情,请前往3.6节。

到此处,本节的剧情结束了,你能够起首下一小节的上学。
以为博主翻译的还足以就点赞帮衬一下啊!

相关文章