参考原文:Writing your first Django app, part 3
本文Python搭建在 Django Compose + Djang 执行Python需进入web server容器中,请参看[第一步:在Mac构建Django 容器]
翻译整理:CKhtml
一个View是一个为特定功能服务的一种网页,例如在本例中有4个View:前端
在Djanog中网页和其余内容经过View来展现,每一个View至关于一个简单的Python函数(或方法,在基于类的View中),在URLconfs中作了URL到View的映射。web
添加到polls/views.pydjango
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.urlsapp
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'), ]
以 http://127.0.0.1:8000/polls/34/ 为例, URL之匹配除域名之外的部分,ROOT_URLCONF里的URL url(r'^polls/', include('polls.urls')),
匹配了 "polls/" 再将剩余部分 "34/" 发送到‘polls.urls’ URLconf 进一步处理,(?P<question_id>[0-9]+)
圆括号用来捕获值,"?P<question_id>" 用来定义将要匹配到的模式的名字。[0-9]+ 匹配1到多个数字。最后将匹配到的34做为参数传给detail方法。函数
每一个View负责返回一个HttpResponse 对象,或者返回异常如Http404
列出最后5个问题:url
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
这样作的缺点时,页面内容写在View的代码里,若是要改变页面的样子,就得修改Python代码。能够用模版系统来把Python跟页面设计区分开来。在setting.py的TEMPLATES设置里描述了Django如何加载和渲染模版。习惯上Django会在每一个安装的APP的目录下查找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.pyrest
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/templates/polls/index.html 并传入一个context。这个context是一个字典,将模版的变量名映射为Pyhon对象。
重写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)
修改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})
建立polls/templates/polls/detail.html
{{ question }}
A shortcut: get_object_or_404()
重写detail方法:
def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question})
之因此让model API 报Http404错误而不是ObjectDoesNotExist异常,是由于若是不这样会形成模型层跟视图层的耦合。或者说views.py不该该关心模型层面的事情,而应该只专一于如何展现,取到什么内容就展现什么。去到的内容是正确的值仍是错误信息,应该是model或者controller的事
一样的get_list_or_404()函数像以前的同样,除了使用filter()而不是get()。当取回的列表为空的时候返回404错误
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>
修改polls/index.html
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
由于这是紧耦合的作法(当你修改项目的URL的时候,还须要去改动模版),可使用模版标记来去掉模版对特定URL路径的依赖,改成:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
这样的好处是polls.urls模块中,名为'detail'的url已经定义好了,根据这个跳转就了,之后若是要修改指向,只要修改polls.urls就好,例如:
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
若是项目中有多个app 不仅一个app有detail View,如何使用模版标记{% url %} template tag
?
在polls/urls.py中加入 app_name = 'polls'
变成
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 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
这样Django就知道如何生成动态的超连接指向了,而去要修改app的URL也只须要修改对应app/urls.py ,无需修改模版。因为模版中每每包含超连接,这样的好处仍是很大的。