Django文档阅读-Day3
Django文档阅读-Day3
Writing your first Django app, part 3
Overview
A view is a “type” of Web page in your Django application that generally serves a specific function and has a specific template. For example, in a blog application, you might have the following views:
- Blog homepage – displays the latest few entries.
- Entry “detail” page – permalink page for a single entry.
- Year-based archive page – displays all months with entries in the given year.
- Month-based archive page – displays all days with entries in the given month.
- Day-based archive page – displays all entries in the given day.
- Comment action – handles posting comments to a given entry.
In our poll application, we’ll have the following four views:
- Question “index” page – displays the latest few questions.
- Question “detail” page – displays a question text, with no results but with a form to vote.
- Question “results” page – displays results for a particular question.
- Vote action – handles voting for a particular choice in a particular question.
In Django, web pages and other content are delivered by views. Each view is represented by a Python function (or method, in the case of class-based views). Django will choose a view by examining the URL that’s requested (to be precise, the part of the URL after the domain name).
Now in your time on the web you may have come across such beauties as “ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”. You will be pleased to know that Django allows us much more elegant URL patterns than that.
A URL pattern is the general form of a URL - for example: /newsarchive/<year>/<month>/
.
To get from a URL to a view, Django uses what are known as ‘URLconfs
’. A URLconf
maps URL patterns to views.
This tutorial provides basic instruction in the use of URLconfs
, and you can refer to URL dispatcher for more information.
一句话概括:Django通过路由映射找到视图函数,处理业务。
Writing more views
Now let’s add a few more views to polls/views.py
. These views are slightly different, because they take an argument:
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)
Wire these new views into the polls.urls
module by adding the following path()
calls:
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'),
]
Take a look in your browser, at “/polls/34/”. It’ll run the detail()
method and display whatever ID you provide in the URL. Try “/polls/34/results/” and “/polls/34/vote/” too – these will display the placeholder results and voting pages.
When somebody requests a page from your website – say, “/polls/34/”, Django will load the mysite.urls
Python module because it’s pointed to by the ROOT_URLCONF
setting. It finds the variable named urlpatterns
and traverses the patterns in order. After finding the match at 'polls/'
, it strips off the matching text ("polls/"
) and sends the remaining text – "34/"
– to the ‘polls.urls’ URLconf
for further processing. There it matches '<int:question_id>/'
, resulting in a call to the detail()
view like so:
detail(request=<HttpRequest object>, question_id=34)
The question_id=34
part comes from <int:question_id>
. Using angle brackets “captures” part of the URL and sends it as a keyword argument to the view function. The :question_id>
part of the string defines the name that will be used to identify the matched pattern, and the <int:
part is a converter that determines what patterns should match this part of the URL path.
There’s no need to add URL cruft such as .html
– unless you want to, in which case you can do something like this:
path('polls/latest.html', views.index),
But, don’t do that. It’s silly.
哈哈,看来将Django团队很排挤在url
中增加后缀名
Writing views that actually do something
Each view is responsible for doing one of two things: returning an HttpResponse
object containing the content for the requested page, or raising an exception such as Http404
. The rest is up to you.
Your view can read records from a database, or not. It can use a template system such as Django’s – or a third-party Python template system – or not. It can generate a PDF file, output XML, create a ZIP file on the fly, anything you want, using whatever Python libraries you want.
All Django wants is that HttpResponse
. Or an exception.
Because it’s convenient, let’s use Django’s own database API, which we covered in Tutorial 2. Here’s one stab at a new index()
view, which displays the latest 5 poll questions in the system, separated by commas, according to publication date:
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
There’s a problem here, though: the page’s design is hard-coded in the view. If you want to change the way the page looks, you’ll have to edit this Python code. So let’s use Django’s template system to separate the design from Python by creating a template that the view can use.
First, create a directory called templates
in your polls
directory. Django will look for templates in there.
Your project’s TEMPLATES
setting describes how Django will load and render templates. The default settings file configures a DjangoTemplates
backend whose APP_DIRS
option is set to True
. By convention DjangoTemplates
looks for a “templates” subdirectory in each of the INSTALLED_APPS
.
Within the templates
directory you have just created, create another directory called polls
, and within that create a file called index.html
. In other words, your template should be at polls/templates/polls/index.html
. Because of how the app_directories
template loader works as described above, you can refer to this template within Django as polls/index.html
.
Template namespacing
Now we might be able to get away with putting our templates directly in polls/templates (rather than creating another polls subdirectory), but it would actually be a bad idea. Django will choose the first template it finds whose name matches, and if you had a template with the same name in a different application, Django would be unable to distinguish between them. We need to be able to point Django at the right one, and the best way to ensure this is by namespacing them. That is, by putting those templates inside another directory named for the application itself.
虽然我们现在可以将模板文件直接放在polls/templates文件夹中(而不是在再建立一个polls子文件夹),但是这样做肯定不好。Django将要选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django没有办法区分它们。我们可以帮助Django区分正确的模板,最简单的方法就是放入它们各自的命名空间,也就是吧这些模板放入一个和自身应用重名的子文件夹里。
思考:
直观上看通过polls/index.html及“应用名/模板名"就可以区分不同应用的模板呀,为什么Django会混淆呢。哈哈哈,猜测:Django在生命周期中会预先加载所有应用的模板文件,为他们创建索引。这样所有的模板文件都在一起。就会出现重名的情况。所以要在templates文件夹中再建立一个与app同名的子文件夹。
Put the following code in that template:
{% 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 %}
Now let’s update our index
view in polls/views.py
to use the template:
from django.http import HttpResponse #http响应在http中
from django.template import loader #html渲染相关操作在templates中
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)) #通过render函数渲染
That code loads the template called polls/index.html
and passes it a context. The context is a dictionary mapping template variable names to Python objects.
Load the page by pointing your browser at “/polls/”, and you should see a bulleted-list containing the “What’s up” question from Tutorial 2. The link points to the question’s detail page.
A shortcut: render()
It’s a very common idiom to load a template, fill a context and return an HttpResponse
object with the result of the rendered template. Django provides a shortcut. Here’s the full index()
view, rewritten:
from django.shortcuts import render #原来shortcuts库是Django给我们的语法糖啊。
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)
Note that once we’ve done this in all these views, we no longer need to import loader
and HttpResponse
(you’ll want to keep HttpResponse
if you still have the stub methods for detail
, results
, and vote
).
The render()
function takes the request object as its first argument, a template name as its second argument and a dictionary as its optional third argument. It returns an HttpResponse
object of the given template rendered with the given context.
render函数本质也是返回一个HttpResponse
,不要忘了文档多次强调视图始终希望返回一个HttpResponse
对象或者一个异常比如Http404
Raising a 404 error
Now, let’s tackle the question detail view – the page that displays the question text for a given poll. Here’s the view:
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})
The new concept here: The view raises the Http404
exception if a question with the requested ID doesn’t exist.
We’ll discuss what you could put in that polls/detail.html
template a bit later, but if you’d like to quickly get the above example working, a file containing just:
polls/templates/polls/detail.html
{{ question }}
will get you started for now.
A shortcut: get_object_or_404()
It’s a very common idiom to use get()
and raise Http404
if the object doesn’t exist. Django provides a shortcut. Here’s the detail()
view, rewritten:
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})
The get_object_or_404()
function takes a Django model as its first argument and an arbitrary number of keyword arguments, which it passes to the get()
function of the model’s manager. It raises Http404
if the object doesn’t exist.
Philosophy
Why do we use a helper function get_object_or_404() instead of automatically catching the ObjectDoesNotExist exceptions at a higher level, or having the model API raise Http404 instead of ObjectDoesNotExist?
Because that would couple the model layer to the view layer. One of the foremost design goals of Django is to maintain loose coupling. Some controlled coupling is introduced in the django.shortcuts module.
为什么我们使用辅助函数呢,而不是自己捕捉错误呢?还有为什么模型不直接抛出错误,而是抛出Http404错误呢?因为这样做会增加模型与视图层的耦合度。指导Django的设计思想之一是保证松耦合。一些受控的耦合将会被被包含在shortcuts库中。
There’s also a get_list_or_404()
function, which works just as get_object_or_404()
– except using filter()
instead of get()
. It raises Http404
if the list is empty.
Use the template system
Back to the detail()
view for our poll application. Given the context variable question
, here’s what the polls/detail.html
template might look like:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
The template system uses dot-lookup syntax to access variable attributes. In the example of {{ question.question_text }}
, first Django does a dictionary lookup on the object question
. Failing that, it tries an attribute lookup – which works, in this case. If attribute lookup had failed, it would’ve tried a list-index lookup.
Method-calling happens in the {% for %}
loop: question.choice_set.all
is interpreted as the Python code question.choice_set.all()
, which returns an iterable of Choice
objects and is suitable for use in the {% for %}
tag.
See the template guide for more about templates.
Removing hardcoded URLs in templates
Remember, when we wrote the link to a question in the polls/index.html
template, the link was partially hardcoded like this:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
The problem with this hardcoded, tightly-coupled approach is that it becomes challenging to change URLs on projects with a lot of templates. However, since you defined the name argument in the path()
functions in the polls.urls
module, you can remove a reliance on specific URL paths defined in your url configurations by using the {% url %}
template tag:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
The way this works is by looking up the URL definition as specified in the polls.urls
module. You can see exactly where the URL name of ‘detail’ is defined below:
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
If you want to change the URL of the polls detail view to something else, perhaps to something like polls/specifics/12/
instead of doing it in the template (or templates) you would change it in polls/urls.py
:
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
Namespacing URL names
The tutorial project has just one app, polls
. In real Django projects, there might be five, ten, twenty apps or more. How does Django differentiate the URL names between them? For example, the polls
app has a detail
view, and so might an app on the same project that is for a blog. How does one make it so that Django knows which app view to create for a url
when using the {% url %}
template tag?
The answer is to add namespaces to your URLconf
. In the polls/urls.py
file, go ahead and add an app_name
to set the application namespace:
from django.urls import path
from . import views
#创建app命名空间
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'),
]
Now change your polls/index.html
template from:
polls/templates/polls/index.html
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
to point at the namespaced
detail view:
polls/templates/polls/index.html
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
When you’re comfortable with writing views, read part 4 of this tutorial to learn the basics about form processing and generic views.
Writing your first Django app, part 4
This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on form processing and cutting down our code.
Write a minimal form
Let’s update our poll detail template (“polls/detail.html”) from the last tutorial, so that the template contains an HTML <form>
element:
<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. Thename
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 datachoice=#
where # is the ID of the selected choice. This is the basic concept of HTML forms.We set the form’s
action
to{% url 'polls:vote' question.id %}
, and we setmethod="post"
. Usingmethod="post"
(as opposed tomethod="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, usemethod="post"
. This tip isn’t specific to Django; it’s good Web development practice in general.forloop.counter
indicates how many times thefor
tag has gone through its loopSince we’re creating a POST form (which can have the effect of modifying data), we need to worry about Cross Site Request Forgeries. Thankfully, you don’t have to worry too hard, because Django comes with a helpful system for protecting against it. In short, all POST forms that are targeted at internal URLs should use the
{% csrf_token %}
template tag.
Now, let’s create a Django view that handles the submitted data and does something with it. Remember, in Tutorial 3, we created a URLconf
for the polls application that includes this line:
path('<int:question_id>/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
:
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
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):
# 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 += 1
selected_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.Note that Django also provides
request.GET
for accessing GET data in the same way – but we’re explicitly usingrequest.POST
in our code, to ensure that data is only altered via a POST call.request.POST['choice']
will raiseKeyError
ifchoice
wasn’t provided in POST data. The above code checks forKeyError
and redisplays the question form with an error message ifchoice
isn’t given.After incrementing the choice count, the code returns an
HttpResponseRedirect
rather than a normalHttpResponse
.HttpResponseRedirect
takes a single argument: the URL to which the user will be redirected (see the following point for how we construct the URL in this case).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 good Web development practice in general.We are using the
reverse()
function in theHttpResponseRedirect
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, thisreverse()
call will return a string like'/polls/3/results/'
where the 3
is the value of question.id
. This redirected URL will then call the 'results'
view to display the final page.
今日收获单词
specific /spəˈsɪfɪk/ 特殊的,特定的
permalink 永久链接
permanent 永久的
archive 把...存档 档案文件
entry 条目,入口,进入
action 功能
come across 偶遇,无意中发现
precise 精确的
wire 打电报,给...装电线
wire into 把...装进
traverse 遍历,穿过,横贯
angle 角度,视角
bracket 支架,把...归为同一类,括号
angle bracket 尖括号
cruft 令人讨厌的东西
stab 尝试,刺,戳
the rest of 其余的
get away with 侥幸做成,侥幸惩罚
bulleted-list 无序列表
idiom 习语,土话
stub 存根,烟蒂
tackle 处理,应对,与人交涉
hardcoded 硬编码
reliance 信赖,信心
differentiate 区分,区别
rundown 概要,纲要
server-side 服务器端
dummy 虚拟的,人体模型,假的,蠢得
portion 部分
Django文档阅读-Day3的更多相关文章
- Django文档阅读-Day1
Django文档阅读-Day1 Django at a glance Design your model from djano.db import models #数据库操作API位置 class R ...
- Django文档阅读-Day2
Django文档阅读 - Day2 Writing your first Django app, part 1 You can tell Django is installed and which v ...
- Django文档阅读之模型
模型 模型是您的数据唯一而且准确的信息来源.它包含您正在储存的数据的重要字段和行为.一般来说,每一个模型都映射一个数据库表. 基础: 每个模型都是一个 Python 的类,这些类继承 django.d ...
- 吴裕雄--天生自然PythonDjangoWeb企业开发:Django文档阅读简介
Django是基于MVC模式的框架,虽然也被称为“MTV”的模式,但是大同小异.对我们来说,需要了解的是无论是MVC模式还是MTV模式,甚至是其他的什么模式,都是为了解耦.把一个软件系统划分为一层一层 ...
- Django文档阅读之执行原始SQL查询
Django提供了两种执行原始SQL查询的方法:可以使用Manager.raw()来执行原始查询并返回模型实例,或者可以完全避免模型层直接执行自定义SQL. 每次编写原始SQL时都要关注防止SQL注入 ...
- Django文档阅读之聚合
聚合 我们将引用以下模型.这些模型用来记录多个网上书店的库存. from django.db import models class Author(models.Model): name = mode ...
- Django文档阅读之查询
创建对象 为了在Python对象中表示数据库表数据,Django使用直观的系统:模型类表示数据库表,该类的实例表示数据库表中的特定记录. 要创建对象,请使用模型类的关键字参数对其进行实例化,然后调用s ...
- Node.js的下载、安装、配置、Hello World、文档阅读
Node.js的下载.安装.配置.Hello World.文档阅读
- 我的Cocos Creator成长之路1环境搭建以及基本的文档阅读
本人原来一直是做cocos-js和cocos-lua的,应公司发展需要,现转型为creator.会在自己的博客上记录自己的成长之路. 1.文档阅读:(cocos的官方文档) http://docs.c ...
随机推荐
- Ubuntu 18.04 将gcc版本降级为5.5版本
Remark: Polynomial algebra 程序由于版本问题只能在gcc 5.0 版本运行, 而ubuntu更新会将gcc 更新到7.0版本,出现冲突(报错:如下) collect2: er ...
- GitHub标星2.6万!Python算法新手入门大全
今天推荐一个Python学习的干货. 几个印度小哥,在GitHub上建了一个各种Python算法的新手入门大全,现在标星已经超过2.6万.这个项目主要包括两部分内容:一是各种算法的基本原理讲解,二是各 ...
- (note)从小白到产品经理之路
学习了云课堂的产品课程,整理出部分笔记,以作备用参考,方便实际运用过程中查看巩固. 1.产品工具:Axure.mindmanager.viso.办公软件wps 2.产品人需要具备的品格 富有同理心,习 ...
- [vijos1048]送给圣诞夜的贺卡<DFS剪枝>
题目链接:https://www.vijos.org/p/1048 很多人一看就想出了思路,不就是一个裸的dfs蛮...但是..在n<=50的情况下,朴素会直接tle..... 然后我就开始剪枝 ...
- CSS样式的4种写法 | 以及选择器的几种用法
CSS样式: 1.内部样式表 <style type="text/css"> 样式表写法 </style> 2.使用link标签,在文档中声明使用 ...
- EOS基础全家桶(五)钱包管理
简介 本篇我们将会学习EOS自带的命令行钱包的使用方法,我们将会使用cleos来控制keosd服务对本地钱包进行管理. 虽然现在市面上已经有很多支持EOS的钱包了,有Web钱包,有app钱包,还有浏览 ...
- 【学习笔记】CART算法
1. 背景介绍 CART(Classification and Regression Trees,分类回归树)算法是一种树构建算法,既可以用于分类,也可以用于回归.它的工作原理是:使用二元切分来处理连 ...
- Sql练习201908210951
表结构: create table SalePlan ( PlanId ,) primary key, GoodsId int, PlanPrice decimal(,) ); go create t ...
- 看完这篇Exception 和 Error,和面试官扯皮就没问题了
在 Java 中的基本理念是 结构不佳的代码不能运行,发现错误的理想时期是在编译期间,因为你不用运行程序,只是凭借着对 Java 基本理念的理解就能发现问题.但是编译期并不能找出所有的问题,有一些 N ...
- .NET Core项目部署到Linux(Centos7)(五)Centos 7安装.NET Core环境
目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...