参考:https://docs.djangoproject.com/en/1.9/intro/tutorial03/#write-views-that-actually-do-something
下面让我们来做一些真正有意义的view页面。一个view应该要么返回一个包含请求页面内容的HttpResponse,或者抛出一个异常(比如Http404)。而在view处理过程中你可以做任何你需要的事情(读取数据库等),也可以利用任何你需要的python库。一切都如你所愿。(有点像controller+view)
django需要的,只是一个HttpResponse,或者异常。
OK,我们利用上次数据库教程中用到的Question和Choice,来把polls的index做成问题展示页面。
polls/views.py:
from django.shortcuts import render
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)其余部分不变。
看起来很清楚,但是这引出了一个问题:我们用到的输出都在views里写死了,一旦修改页面需要修改views代码。所以我们利用django的模版系统来建立一个view可以用的模版。
首先,你需要在"polls"目录下建立一个"templates"目录。django将会在这个目录下寻找模版文件。关于django的模版设置可以参看:https://docs.djangoproject.com/en/1.9/ref/settings/#std:setting-TEMPLATES。默认情况下,django的模版会去寻找你的apps的templates文件夹寻找模版。
在templates文件夹建立好之后,我们再建立一个polls文件夹,然后在其中建立index.html文件。这样,我们的路径看起来就像mysite/polls/tempaltes/polls/index.html。django去寻找的时候,会在我们的polls/templates下寻找到polls/index.html文件。这样的路径虽然看起来有点怪异,但是尽量不要省略到后边的polls目录,因为django如果找到多个apps下的templates文件夹下有重路径重名的文件时是分不出来哪个是哪个的。
修改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 %}同时更新polls/views.py:
from django.shortcuts import render
from django.http import HttpResponse
from .models import Question
from django.template import loader
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)
template = loader.get_template('polls/index.html')
context = {
'latest_question_list' : latest_question_list
}
return HttpResponse(template.render(context, request))这段代码会调用polls/index.html并传递context参数。context是一个包含变量和值的dict。来访问:http://localhost:8000/polls/,如下效果:
页面生成成功!
这个index方法的写法是正统写法(读取template,填入context,返回HttpResponse)。此外,django还提供了一种简单的写法:render()。我们用它来覆盖刚才的index:
polls/views.py
from django.shortcuts import render
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)
# template = loader.get_template('polls/index.html')
# context = {
# 'latest_question_list' : latest_question_list
# }
# return HttpResponse(template.render(context, request))
context = {'latest_question_list' : latest_question_list}
return render(request, 'polls/index.html', context)可见,我们并不需要import loader和HttpResponse了(代码里仍然import了是因为余下的几个方法还是返回的HttpResponse)。render方法第一个参数为request对象,第二个参数为模版文件名,第三个参数为变量字典。他返回一个HttpResponse。
学习了正常页面之后,让我们来看看如何声称Http404错误。
让我们简单修改一下detail方法:
from django.shortcuts import render
from django.http import Http404
from django.http import HttpResponse
from .models import Question
......
def detail(request, question_id):
# return HttpResponse("You're looking at question %s." % 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})
(把render放在try块中也不影响结果)
同时简单新建一个polls/templates/polls/detail.html文件:{{ question }}让我们来看看结果。访问存在的question时:
访问不存在的question时:
是一个详细的带debug值的页面。根据提示,修改mysite/settings.py中:
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ['*']
部分,可见标准standard error页面:
我们设定的404信息就不见了。
刚才的写法也是非常正统的:尝试get相应对象。对象不存在时获取Exception,抛出异常。下面再介绍一个简单写法:get_object_or_404()。views样例如下:
from django.shortcuts import render, get_object_or_404
......
def detail(request, question_id):
# return HttpResponse("You're looking at question %s." % question_id)
# try:
# question = Question.objects.get(pk=question_id)
# return render(request, 'polls/detail.html', {'question': question})
# except Question.DoesNotExist:
# raise Http404("Question does not exist")
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question':question})get_object_or_404使用request作为第一参数,以及任意长度的参数作为传递给get()方法的参数。如果object不存在则返回Http404。为何要有这么一个简写的方法呢?因为原来的方法容易导致model和view紧耦合。现在最新的潮流是使用松耦合。
类似的shortcut方法参加:https://docs.djangoproject.com/en/1.9/topics/http/shortcuts/#module-django.shortcuts。
下面让我们来更多的了解模版页。回到detail方法,修改polls/detail.html页面:
<h1>{{ question.question_text}} </h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{choice.choice_text}}</li>
{% endfor %}
</ul>可见模版系统使用了dot-lookup语法来寻找对象和对象的属性/方法。在{% for %}方法中调用了question.choice_set.all,相当于python中的question.choice_set.all()方法。关于他们的用法参考:https://docs.djangoproject.com/en/1.9/topics/templates/。
进行到这里,一切似乎都很美好。但是设想一下,如果我们修改了detail的页面地址,比如从polls/{id}/变成polls/specifies/{id},那么很多硬写死的url链接就需要去修改(也许你已经忘了,在polls/index.html里有
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>这个东西(卧槽)。。当模版多起来的时候,修改这些写死的地方就会变成噩梦。好在django提供了一个url方法来搞定:
<li><a href="{% url 'detail' question.id%}">{{ question.question_text }}</a></li>
urlpatterns = [
......
# ex: /polls/5/
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
......
]在页面中的url方法就回去找到这个配置,并把相对应的url读取出来。 例如我们修改urls.py为
url(r'^something/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),那么在index中,点击question,我们就会自动跳转到:
注意url,已经变成了something/1了。
如果网站安装了多个apps,而某些apps的url具有相同的配置,那么,你需要对url进行namespace定义。方法是:在app/urls.py中,定义app_name属性,例如:
polls/urls.py:
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
# ex: /polls/
url(r'^$', views.index, name='index'),
# ex: /polls/5/
url(r'^something/(?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'),
]
在相应的页面上,就可以使用:
<li><a href="{%url 'polls:detail' question.id%}">{{ question.question_text }}</a></li>注意polls:detail。
7425



被折叠的 条评论
为什么被折叠?



