视图 views
在博客应用中,有下列视图:
博客homepage - 显示最近几个词条。
词条“detail”页 - 单个词条的永久连接页。
基于年份的存档页
基于月份的存档页
基于天的存档页
评论
在poll应用中,有下列4个视图:
Question ‘index’ page
Question 'detail' page
Question 'results' page
Vote action
Django中,web页及其他内容通过视图传递。每个视图由一个简单Python函数(或者方法,基于类的视图实例)表示。Django通过检查请求的URL来选择一个视图(为了更精准,URL部分在域名之后)。
为了从URL获取视图,Django采用‘URLconfs’。 URLconfs映射URL模式到视图。
写更多的视图 Writing more views
编辑polls/views.py
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
def index(request):
return HttpResponse("hello, world. You're at the polls index.")
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(request % question_id)
def vote(request,question_id):
return HttpResponse("You're voting on question %s." %question_id)
编辑polls/urls.py
from django.urls import path
##from django.conf.urls import url
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'),
]
运行测试:
root@imhqq-Lenovo-H5050:/home/imhqq/share/django_dev/mysite# python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
December 30, 2017 - 15:19:37
Django version 2.0, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Write views that actually do something
每个视图负责做一到两件事:返回一个包含请求页内容的HttpResponse对象,或者弹出一个Http404异常。
视图可以从从数据库读记录。视图也可以使用模板系统,比如说Django的,或者第三方Python模板系统。
视图也可以凭空生成一个PDF文件,输出XML,生成一个ZIP文件,任何你想要的,使用你想要的任何Python库。
编辑polls/views.py
from django.shortcuts import render
# Create your views here.
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)
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(request % question_id)
def vote(request,question_id):
return HttpResponse("You're voting on question %s." %question_id)
上述视图是硬编码。如果想要改变网页显示的方式,将不得不编辑Python代码。使用创建的视图可以使用的Django模板系统来从Python中分离设计。
Django创建用户模板
首先,在polls下创建一个templates文件。
默认mysite/settings.py中,TEMPLATES的设置APP_DIRS为True.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
为方便起见,DjangoTemplates在每个INSTALLED_APPS中搜索“templates”的子路径。
在创建的templates路径下,创建另一个称为polls的路径,在polls下创建一个index.html文件。也就是说,模板在polls/templates/polls/index.html下。在Django内部,可通过polls/index.html引用该模板。
编辑polls/templates/polls/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/poll/{{ question.id}}/">{{ question.question_text }}></a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
在polls/views.py中更新index视图使用模板。
编辑polls/views.py文件
from django.shortcuts import render
# Create your views here.
#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]
#add for using template 2017-12-30
#template = loader.get_template('polls/index.html')
#context = {'latest_question_list':latest_question_list}
#return HttpResponse(template.render(context,request))
#去掉下面这些硬编码
#output = ', '.join([q.question_text for q in latest_question_list])
#return HttpResponse(output)
#使用render重写,使用render载入模板,不再需要使用loader及HttpResponse了。
context = {'latest_question_list':latest_question_list}
return render(request,'polls/index.html',context)
代码载入polls/index.html模板,并传入一个context。这个context对Python对象而言是一个字典映射模板变量名。
快捷方式:render():
render()是载入模板的通常用法,填充context并返回一个HttpResponse对象作为提供模板的结果。代码修改如上。
这样不再需要import loader和HttpResponse了。
render()函数采用request对象作为第一个入参,模板名字作为第二个入参,字典作为可选第三个入参。
返回一个由指定模板提交指定context而来的HttpResponse对象。
弹出404错误
处理detail视图的问题 - 为指定poll显示question context页面。
编辑polls/views.py
ef detail(request,question_id):
#下面的硬编码删除
#return HttpResponse("You're looking at Question %s." %question_id)
#处理Http404错误
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})
编辑polls/templates/polls/detail.html
{{ question }}
快捷方式: get_object_or_404()
重写detail()视图
编辑polls/views.py
from django.shortcuts import get_object_or_404
def detail(request,question_id):
#下面的硬编码删除
#return HttpResponse("You're looking at Question %s." %question_id)
#处理Http404错误
#try:
# question = Question.objects.get(pk=question_id)
#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})
采用模板系统
编辑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做字典查找,失败之后在尝试属性查找。如果属性查找失败,尝试list-index查找。
移除模板中的硬编码URLs
模板中的硬编码示例:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>对于这种硬编码,紧耦合方法,当改变项目中的多个模板的URLs时将带来许多问题。
考虑到在path()函数中的polls.urls模块中已经定义了名字参数,可以通过如下方法移除模板中的硬编码。
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>这是通过查找polls.urls模块中的URL定义的方式实现的。
在polls/urls.py中:
path('<int:question_id>/',views.detail,name='detail'),
如果想要改变detail的URL到/polls/specifies/12/,那么要改变/polls/urls.py如下:
path('/specifics/<int:question_id>/',views.detail,name='detail'),
Namespacing URL names
解决一个项目中多个app的问题,如何区分这些app之间的URL名字?例如,polls app有一个detail视图,另一个app也有一个detail视图。解决办法是在URLconf中增加命名空间。
编辑polls/urls.py
from django.urls import path
##from django.conf.urls import url
from . import views
app_name = 'polls'
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'),
]
同时修改/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>