“全能”选手—Django 1.10文档中文版Part2
欢迎大家访问我的个人网站《刘江的博客和教程》:www.liujiangblog.com
主要分享Python 及Django教程以及相关的博客
3.2 模型和数据库Models and databases
目录
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 删除模板中硬编码的URLs
- 2.5.7 URL names的命名空间
2.6 第一个DJango app,Part 4:表单和泛型视图
- 2.6.1 编写一个简单的form
- 2.6.2 使用泛型视图:减少代码冗余
2.5 第一个Django app,Part 3:视图和模板
本章承上启下,主要介绍Django的视图概念。
2.5.1 概览
一个视图就是一个网页“类型”,通常提供特定的功能或特定的模板。例如:在一个博客应用中,你可能会看到下列视图:
- 博客主页:显示最新发布的一些内容
- 条目详细页面:每个条目对应的永久页面
- 基于年的文章页面:显示指定年内的所有博客文章
- 基于月的文章页面:显示指定月内的所有博客文章
- 基于天的文章页面:显示指定日内的所有博客文章
- 发布评论:处理针对某篇博客发布的评论
在我们的投票应用中,我们将建立下面的视图:
- 问卷“index”页:显示最新的一些问卷
- 问卷“detail”页面:显示一个问卷的详细文本内容,没有调查结果但是有一个投票或调查表单。
- 问卷“results”页面:显示某个问卷的投票或调查结果。
- 投票动作页面:处理针对某个问卷的某个选项的投票动作。
在Django中,网页和其它的一些内容都是通过视图来分发的。视图表现为一个简单的Python函数(在基于类的视图中称为方法)。Django通过对比请求的URL地址来选择对应的视图。
在你平时的网页上,你可能经常会碰到类似“ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”的url。庆幸的是Django支持使用更加简介的URL模式,而不需要编写上面那种复杂的url。
一个URL模式其实就是一个URL通用表达式,例如:/newsarchive///。为了使得URL模式映射到对应的视图,DJango使用URLconfs来完成这一工作。本教程介绍基本的URLconfs使用方法,更多的内容,请参考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文件里设置的根URL配置文件。在该文件里,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<question_id>[0-9]+)而来。在正则表达式中通过一个双圆括号,Django会捕获它匹配到的值并传递给对应的视图,作为视图的位置参数之一,而?P<question_id>则表示我要给这个捕获的值指定一个特殊的变量名,在视图中可以通过question_id这个变量名随意的引用它,形成一个关键字参数,不用考虑参数的位置。至于[0-9]+则是一个很简单的原生正则表达式,用于匹配一系列连续的数字,它匹配到的值也就是具体要传递的参数值。
所有的URL模式都是正则表达式,Django不限制你在url模式中的书写方式。但是,你真的没必要书写一个如下的较为愚蠢的包含".html"的模式,它显然是没必要,不够简练的:
url(r'^polls/latest\.html$', views.index),
你完全可以用下面的模式代替上面的:
url(r'^polls/latest$', views.index),
2.5.3 编写能实际干点活的视图
前面我们说过,每个视图至少做两件事之一:返回一个包含请求页面的HttpResponse对象或者弹出一个类似Http404的异常。其它的则随你便,你爱干嘛干嘛。
你的视图可以从数据库读取记录,或者不读。你可以使用Django提供的模板系统或者第三方的Python模板系统,或者干脆啥也不用。你可以生成PDF文件、输出XML,创建ZIP压缩文件,任何你想做的事,使用任意你想用的Python库。
而Django想要的只有HttpResponse或者一个异常。
因为这样很简便,接下来让我们使用DJango自己的数据库API,我们在上面的教程里介绍过的。下面是一个新的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)
# 下面是那些没改动过的视图(detail, results, vote)
但是这里仍然有个问题:在视图中的页面时硬编码的。如果你想改变页面的显示,就必须修改这里的Python代码。因此,让我们来使用Django提供的模板系统,解耦视图和模板之间的联系。
首先,在polls目录下创建一个新的templates目录,Django会在它里面查找模板文件。
这里解释一下:Django项目的settings配置文件中定义了如何加载和渲染模板。默认的设置
是DjangoTemplates后端,并且APP_DIRS参数被设置为True。作为惯例,Django也会寻找每个在INSTALLED_APPS配置项里注册过的app本身目录下的templates子目录。
回到你刚才创建的templates目录中,再创建一个新的子目录名叫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文件,并传递给它一个参数,这个参数是一个字典,包含了模板变量名和python对象之间的映射关系。
在浏览器中通过访问“/polls/”,你可以看到一个列表,包含“What’s up”的问卷,以及连接到其对应详细内容页面的链接点。
快捷方式: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)
render()函数的第一个位置参数是请求对象(就是view函数的第一个参数),第二个位置参数是模板,还可以有一个可选的第三参数---一个字典,包含需要传递给模板的数据。最后render函数返回一个经过字典数据渲染过的模板封装而成的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则是查询一个结果的方法,和filter是一个和多个的区别!)
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 删除模板中硬编码的URLs
在polls/index.html文件中,还有一部分硬编码存在,也就是herf里的“/polls/”部分:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
其中的紧耦合对于代码修改非常不利。 但是,我们前面给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视图的URL更换为polls/specifics/12/,那么你不需要在模板中重新修改url地址了,仅仅只需要在polls/urls.py文件中,将对应的正则表达式改成下面这样的就行了:
# 添加新的单词'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
2.5.7 URL names的命名空间
本教程例子中,只有1个app也就是polls,但是在现实中很显然会有5个、10个、更多的app同时存在一个项目中。Django是如何区分这些app之间的URL name呢?
答案是使用URLconf的命名空间。在polls/urls.py文件的开头部分,添加一个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 第一个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请求,就必须考虑一个跨站请求伪造的问题,简称CSRF(具体含义请百度)。Django为你提供了一个简单的方法来避免这个困扰,那就是在form表单内添加一条{% csrf_token %}标签,标签名不可更改,固定格式,位置任意,只要是在form表单内。但是(译者注),这个方法对form表单的提交方式方便好使,但是如果是用ajax的方式提交数据,那么就很费劲了。个人认为不如直接在Django配置中关闭这个看似有作用,其实然并卵的CSRF得了。
现在,让我们创建一个处理提交过来的数据的视图。前面我们已经写了一个“占坑”的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是一个类似字典的对象,允许你通过键名访问提交的数据。本例中,request.POST[’choice’]返回被选择选项的ID,并且值的类型永远是string字符串,那怕它看起来像数字,记住了!!!!同样的,你也可以用类似的手段获取GET请求发送过来的数据,一个道理。
- request.POST[’choice’]有可能触发一个KeyError异常,如果你的POST数据里没有提供choice键值,在这种情况下,上面的代码会返回表单页面并给出错误提示。译者注:通常我们会给个默认值,防止这种异常的产生,例如:request.POST[’choice’,None],一个None解决所有问题。
- 在选择计数器加一后,返回的是一个HttpResponseRedirect而不是先前我们常用的HttpResponse。HttpResponseRedirect需要一个参数:重定向的URL。这里有一个建议,当你成功处理POST数据后,应当保持一个良好的习惯,始终返回一个HttpResponseRedirect。这不仅仅是对Django而言,它是一个良好的WEB开发习惯。
- 我们在上面HttpResponseRedirect的构造器中使用了一个reverse()函数。它能帮助我们避免在视图函数中硬编码URL。它首先需要一个我们在URLconf中指定的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视图的代码非常相似,有点冗余,这是一个程序猿不能忍受的。他们都具有类似的业务逻辑,实现类似的功能:通过从URL传递过来的参数去数据库查询数据,加载一个模板,利用刚才的数据渲染模板,返回这个模板。由于这个过程是如此的常见,Django又很善解人意的帮你想办法偷懒了,它提供了一种快捷方式,名为“泛型视图”系统。
现在,让我们来试试看将原来的代码改为使用泛型视图的方式,整个过程分三步走:
- 改变URLconf
- 删除一些旧的无用的视图
- 采用基于泛型视图的新视图
注释:Django官方的“辩解”
为什么本教程的代码来回改动这么频繁?
答:通常在写一个Django的app时,我们一开始就要决定是使用泛型视图还是不用,而不是等到代码写到一半了才重构你的代码成泛型视图。但是本教程为了让你清晰的理解视图的内涵,“故意”走了一条比较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'),
]
请注意:在上面的的第2,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(译者注:它们是作为父类被继承的)。这两者分别代表“显示一个对象的列表”和“显示特定类型对象的详细页面”的抽象概念。
每一种泛型视图都需要知道它要作用在哪个模型上,这通过model属性提供。
DetailView泛型视图需要从URL捕获到的称为"pk"的主键值,因此我们在url文件中将2和3条目的
<question_id>
修改成了<pk>
。
默认情况下,DetailView泛型视图使用一个称作<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泛型视图使用一个默认模板称为<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节。
到这里,本节的内容结束了,你可以开始下一小节的学习。
觉得博主翻译的还可以就点赞支持一下吧!
“全能”选手—Django 1.10文档中文版Part2的更多相关文章
- “全能”选手—Django 1.10文档中文版Part1
本文是博主翻译的Django1.10版本官方文档的第一部分,如时间充裕,争取一直翻译下去,经验不足,或有错漏,敬请指正. 另外对于公开文档进行翻译的版权问题不是很清楚,如有侵权请联系我! 另外,要转载 ...
- “全能”选手—Django 1.10文档中文版Part4
第一部分传送门 第二部分传送门 第三部分传送门 3.2 模型和数据库Models and databases 3.2.2 查询操作making queries 3.3.8 会话sessions 2.1 ...
- “全能”选手—Django 1.10文档中文版Part3
Django 1.10官方文档的入门教程已经翻译完毕,后续的部分将不会按照顺序进行翻译,而是挑重点的先翻译. 有兴趣的可以关注我的博客. 第一部分传送门 第二部分传送门 第四部分传送门 3.2 模型和 ...
- Django 1.10文档中文版Part2
目录 2.5 第一个Django app,Part 3:视图和模板 2.5.1 概览 2.5.2 编写更多的视图 2.5.3 编写能实际干点活的视图 2.5.4 404错误 2.5.5 使用模板系统 ...
- Django 1.10文档中文版Part1
目录 第一章.Django1.10文档组成结构1.1 获取帮助1.2 文档的组织形式1.3 第一步1.4 模型层1.5 视图层1.6 模板层1.7 表单1.8 开发流程1.9 admin站点1.10 ...
- Django 1.10文档中文版Part4
2.10 高级教程:如何编写可重用的apps 2.10.1 重用的概念 The Python Package Index (PyPI)有大量的现成可用的Python库.https://www.djan ...
- Django 1.10文档中文版Part3
目录 2.7 第一个Django app,Part 5:测试 2.7.1 自动化测试介绍 2.7.2 基本的测试策略 2.7.3 编写我们的第一个测试程序 2.7.4 测试一个视图 2.7.5 测试越 ...
- django 中文入门文档
django中文入门文档:阅读地址
- JAVA - JDK 1.8 API 帮助文档-中文版
JAVA - JDK 1.8 API 帮助文档-中文版 百度云链接: https://pan.baidu.com/s/1_7FFadw1a6J0qTfx2FzqPQ 密码: 41n4
随机推荐
- iphone 下滚动条卡顿解决办法
-webkit-overflow-scrolling:touch; -webkit-text-size-adjust:none;
- Android课程---远程服务器存储
在使用Volley进行获取数据时,需要事先准备环境:在libs里面导入一个Volley.jar包,在网上都有,可以下载下来导入,或者自己电脑上有DT的,自己合成一个包也行. WebActivity.j ...
- xcodebuild编译ipa
#!/bin/sh # autoBuild.sh # CTest # # Created by Ethan on 14-11-3. # Copyright (c) 2014年 Ethan. All r ...
- 简化 Web 应用程序与 Windows Azure Active Directory、ASP.NET 和 Visual Studio 的集成
大家好! 今天的博文深入讨论我们今天推出的开发人员工具和框架中的一些新功能.我们通过与 ASP.NET 和 Visual Studio 团队合作开发了一些重大的增强功能,让开发人员能够轻松使用 Win ...
- 如何让你的JavaScript代码更加语义化
语义化这个词在 HTML 中用的比较多,即根据内容的结构化选择合适的标签.其作用不容小觑: 赋予标签含义,让代码结构更加清晰,虽然我们可以在标签上添加 class 来标识,但这种通过属性来表示本体的形 ...
- 探索C#之虚拟桶分片
阅读目录 背景 虚拟桶(virtual buckets) 实现 总结 背景 关于数据分片讨论最多的是一致性hash,然而它并不是分布式设计中的银弹百试百灵. 在数据稳定性要求比较高的场景下它的缺点是不 ...
- Apache Mina实战
Mina介绍 Mina可以用于快速的开发基于网络通信的应用,特别是在开发手机端的游戏应用时,使用的较为普遍.本文简单介绍了一个用Mina搭建的一个简易讨论组,通过该应用可以对Mina的基本用法用途有个 ...
- 七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL
本节又带了一些常用的,却很难理解的问题,本节从文件上传功能的实现引出了线程使用,介绍了线程饥饿的解决方法,异常处理方法,了解RouteTable自定义路径 . 系列文章 七天学会ASP.NET MVC ...
- spring事务管理器设计思想(一)
在最近做的一个项目里面,涉及到多数据源的操作,比较特殊的是,这多个数据库的表结构完全相同,由于我们使用的ibatis框架作为持久化层,为了防止每一个数据源都配置一套规则,所以重新实现了数据源,根据线程 ...
- ABP(现代ASP.NET样板开发框架)主题线下交流会(上海)开始报名了!
点这里进入ABP系列文章总目录 ABP主题线下交流会(上海)开始报名了 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称.它是采用最佳实践和流行技术 ...