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
valueof each radio button is the associated question choice’s ID. Thenameof 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
actionto{% 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.counterindicates how many times thefortag 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.POSTis 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.POSTvalues are always strings.Note that Django also provides
request.GETfor accessing GET data in the same way – but we’re explicitly usingrequest.POSTin our code, to ensure that data is only altered via a POST call.request.POST['choice']will raiseKeyErrorifchoicewasn’t provided in POST data. The above code checks forKeyErrorand redisplays the question form with an error message ifchoiceisn’t given.After incrementing the choice count, the code returns an
HttpResponseRedirectrather than a normalHttpResponse.HttpResponseRedirecttakes 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
HttpResponseRedirectafter 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 theHttpResponseRedirectconstructor 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 ...
随机推荐
- ysoserial-C3P0 分析
环境准备: pom: <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> < ...
- 了解1D和3D卷积神经网络 | Keras
当我们说卷积神经网络(CNN)时,通常是指用于图像分类的2维CNN.但是,现实世界中还使用了其他两种类型的卷积神经网络,即1维CNN和3维CNN.在本指南中,我们将介绍1D和3D CNN及其在现实世界 ...
- SQL Server中创建sde数据库
在ArcCatalog或者ArcMap中打开ArcToolBox工具箱. 在工具箱中,找到创建企业级地理数据库工具,依次为数据管理工具→地理数据库管理→创建企业级地理数据库,如图所示. 双击打开创建企 ...
- Chrome 经典插件
记录几个很喜欢的 Chrome 插件,怕之后找不到了. 1. Dark Theme 很喜欢的一个黑色主题! 2. Volume Booster 能把音量提高2倍的小插件!好用! 3. Looper f ...
- 工作日志,Excel导入树结构数据
目录 1. 前言 2. 需求分析 2.1 需求难点 2.2 解决难点 2.3 表格设计 3. 功能实现 3.1 一个分枝 3.2 一个分枝多个树叶 3.3 多个分枝多个树叶 4. 代码事例 4.1 目 ...
- 十进制转化为非十进制C++代码
还是先为大家介绍一下原理吧. 假设余数为 r ,十进制数为 n :(拆分为整数 zs ,余数 ys) 对 zs:需要将 zs 除 r 取余数,直到商为 0 停止,将余数倒序排列即可. 对 ys:需要将 ...
- javascript原生 实现数字字母混合验证码
实现4位数 数字字母混合验证码(数字+大写字母+小写字母) ASCII 字符集中得到3个范围: 1. 48-57 表示数字0-9 2. 65-90 表示大写字母 3. 97-122 表示小写字母 范围 ...
- 认识STM32芯片
STM32中的ST指的是意法半导体,M是Microelectronics的缩写,32表示32位,即意法半导体公司开发的32位微控制器 ST官网:https://www.st.com/content/s ...
- JDBCUtils,根据当前MySQL数据库下面的表生成java实体类
自己简单写的JDBCUtils,可以根据当前数据库下面的表生成java实体类,代码萌新,请多多包涵. 初始化配置: //驱动程序名//不固定,根据驱动 static String driver = & ...
- php 直接跳出嵌套循环
break 结束当前 for,foreach,while,do-while 或者 switch 结构的执行. break 可以接受一个可选的数字参数来决定跳出几重循环. <?php $arr = ...