Writing your first Django app, part 3
这节主要是讲前台页面的创建
在我们的poll应用中,主要有以下4个view:
- Poll “index” page – displays the latest few polls.
- Poll “detail” page – displays a poll question, with no results but with a form to vote.
- Poll “results” page – displays results for a particular poll.
- Vote action – handles voting for a particular choice in a particular poll.
这里的view层相当于一个controller层,请求会通过url映射访问view中的方法,view再与后台的model层交互。
创建文件polls/views.py,作为poll应用的view层,编辑为以下内容:
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the poll index.")为了调用view层,我们需要映射到一个url,因此我们需要一个URLconf,我们在polls文件夹下创建一个urls.py的文件,现在你的文件夹结构应该像这样:
polls/ __init__.py admin.py models.py tests.py urls.py views.py
urls.py的内容为:
from django.conf.urls import patterns, url from polls import views urlpatterns = patterns('', url(r'^$', views.index, name='index') )
下一步是找到根URLconf,创建mysite/urls.py,内容为:
from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^polls/', include('polls.urls')), url(r'^admin/', include(admin.site.urls)), )这里
include('polls.urls')
就可以看到页面上面有 “Hello, world. You’re at the poll index.”
(二)编写更多的view
继续编辑polls/views.py文件:
def detail(request, poll_id): return HttpResponse("You're looking at poll %s." % poll_id) def results(request, poll_id): return HttpResponse("You're looking at the results of poll %s." % poll_id) def vote(request, poll_id): return HttpResponse("You're voting on poll %s." % poll_id)然后编辑polls/urls.py文件:
from django.conf.urls import patterns, url from polls import views urlpatterns = patterns('', # ex: /polls/ url(r'^$', views.index, name='index'), # ex: /polls/5/ url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'), # ex: /polls/5/results/ url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'), # ex: /polls/5/vote/ url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'), )然后在浏览器输入 ...../polls/34/ ,就会调用这里的detail方法。同理results和vote的调用。
(三)编写可以做一些事情的VIEW
目前的view方法智能返回一个HttpResponse对象,或者返回一个Http404
view也可以从数据库读取信息,下面我们就用view访问数据库:
1、编辑polls/views.py文件,我们的index页面将会显示最近的5个poll对象
from django.http import HttpResponse from polls.models import Poll def index(request): latest_poll_list = Poll.objects.order_by('-pub_date')[:5] output = ', '.join([p.question for p in latest_poll_list]) return HttpResponse(output)
这里有个问题,就是页面的布局是硬编码在这个view方法中,解决方法是创建一个模板让view方法可以调用。
首先,在polls文件夹里创建子文件夹templates,然后在templates文件夹下创建polls文件夹,在polls文件夹下创建文件index.html,目录结构为:
polls/templates/polls/index.html
因为模板加载器知道如何加载模板,所以我们可以用polls/index.html代替上面的路径。
然后把下面的代码粘贴到index.html中:
{% if latest_poll_list %} <ul> {% for poll in latest_poll_list %} <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %}然后编辑polls/views.py,在view中使用模板:
from django.http import HttpResponse from django.template import Context, loader from polls.models import Poll def index(request): latest_poll_list = Poll.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = Context({ 'latest_poll_list': latest_poll_list, }) return HttpResponse(template.render(context))简洁写法:render()
Django提供了一个上面方法的简介版本:
from django.shortcuts import render from polls.models import Poll def index(request): latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] context = {'latest_poll_list': latest_poll_list} return render(request, 'polls/index.html', context)使用render()方法,得到的结果与上面的是一样的
(四)引发404异常
在polls/views.py中加入找不到对象时的404异常
from django.http import Http404 # ... def detail(request, poll_id): try: poll = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404 return render(request, 'polls/detail.html', {'poll': poll})然后编辑polls/details.html模板,为了方便,仅加入以下内容:
{{ poll }}现在如果访问了不存在的poll id,就会看到一个404异常的页面
简洁写法:get_object_or_404()
get_object_or_404()是上面方法的一个简写版本:
from django.shortcuts import render, get_object_or_404 # ... def detail(request, poll_id): poll = get_object_or_404(Poll, pk=poll_id) return render(request, 'polls/detail.html', {'poll': poll})
(五)使用模板系统
回到polls/details.html,改为下面的内容:
<h1>{{ poll.question }}</h1> <ul> {% for choice in poll.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>这样detail页面的外观就改变了
(六)删除在模板文件里的硬编码url
打开polls/index.html,将一个链接标签:
<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>改为:
<li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>这样即时你在polls/views.py中修改某个方法的url地址,这里的链接仍然可用。
(七)URL名字的命名空间
目前我们的项目只有一个polls的应用,实际中可能有5,6或者很多的应用,我们的django如何区别在不同的应用中同时含有相同的view名字
解决方法是在根URLconf中增加namespaces属性,在mysite/urls.py中,修改如下:
from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^polls/', include('polls.urls', namespace="polls")), url(r'^admin/', include(admin.site.urls)), )
然后修改polls/index.html 中的:
<li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>
改为加namespaces的名字:
<li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>