入门笔记翻译整理自:https://docs.djangoproject.com/en/1.8/
*该笔记将使用一个关于投票网络应用(poll application)的例子来阐述Django的用法。
Public interface - views.
1. 定义
视图(View)是Django应用中用于实现某一特定功能的Web页面。比如,一个博客可以有博客展示页面,博客创建页面,评论页面。
2. 视图示例
写入代码
1 #polls/views.py 2 3 from django.http import HttpResponse 4 5 def index(request): 6 return HttpResponse("Hello, world. You‘re at the polls index.")
为了调用视图,我们需要将它映射到一个URL上,因此在polls目录下创建urls.py,最终目录结构如图所示
1 polls/ 2 __init__.py 3 admin.py 4 models.py 5 tests.py 6 urls.py 7 views.py
在polls/urls.py中添加以下代码
1 # polls/urls.py 2 3 from django.conf.urls import url 4 5 from . import views 6 7 urlpatterns = [ 8 url(r‘^$‘, views.index, name=‘index‘), 9 ]
将根目录中的URLconf定位至polls/urls中,使用include()方法:
1 # mysite/urls.py 2 3 from django.conf.urls import include, url 4 from django.contrib import admin 5 6 urlpatterns = [ 7 url(r‘^polls/‘, include(‘polls.urls‘)), 8 url(r‘^admin/‘, include(admin.site.urls)), 9 ]
现在可以通过http://localhost:8000/polls/进入polls应用的视图。
url()方法有四个参数,必填两个:regex, view;选填两个:kwargs, name。其中,regex对模式(pattern)进行匹配,不区分GET和POST;完成匹配后,Django会调用view函数,并将HttpRequest和其他参数传入view函数中;kwargs将关键字参数传入view函数中;name可以对URL 命名
3. 更多视图示例
向polls/views.py中添加更多视图,和前面不同,这些视图需要接收参数
1 # polls/views.py 2 3 def detail(request, question_id): 4 return HttpResponse("You‘re looking at question %s." % question_id) 5 6 def results(request, question_id): 7 response = "You‘re looking at the results of question %s." 8 return HttpResponse(response % question_id) 9 10 def vote(request, question_id): 11 return HttpResponse("You‘re voting on question %s." % question_id)
将这些视图映射到polls.urls
1 # polls/urls.py 2 3 from django.conf.urls import url 4 5 from . import views 6 7 urlpatterns = [ 8 # ex: /polls/ 9 url(r‘^$‘, views.index, name=‘index‘), 10 # ex: /polls/5/ 11 url(r‘^(?P<question_id>[0-9]+)/$‘, views.detail, name=‘detail‘), 12 # ex: /polls/5/results/ 13 url(r‘^(?P<question_id>[0-9]+)/results/$‘, views.results, name=‘results‘), 14 # ex: /polls/5/vote/ 15 url(r‘^(?P<question_id>[0-9]+)/vote/$‘, views.vote, name=‘vote‘), 16 ]
Django实现视图的逻辑如下,以用户访问"/polls/34/"为例:
首先,Django寻找‘^polls/‘的相应匹配;
然后,Django会剥离匹配的字符串"polls/",同时将剩下的文本"34/"发送至‘polls.urls‘;
最后,在‘polls.urls‘的URLconf中进一步匹配r‘^(?P<question_id>[0-9]+)/$‘,并调用detail()视图。
4. 视图再举例
每一个视图都必须完成两个事件之一:返回HttpResponse,或者Http404。其余取决于应用需求。
1 # polls/views.py 2 3 from django.http import HttpResponse 4 5 from .models import Question 6 7 def index(request): 8 latest_question_list = Question.objects.order_by(‘-pub_date‘)[:5] 9 output = ‘, ‘.join([p.question_text for p in latest_question_list]) 10 return HttpResponse(output) 11 # Leave the rest of the views (detail, results, vote) unchanged
但是这里有一个问题,视图页面是硬编码的(hard-coded)。推荐将模板和Python代码独立。
首先,创建polls/templates目录。Django会在该目录下寻找模板。TEMPLATES设置中的默认后台DjangoTemplates会在每个INSTALLED_APP下寻找templates子目录。
然后,创建polls/templates/polls/index.html。这里创建第二个polls子目录的目的在于,区分不同应用下相同名称的index.html文件。
接着,修改index.html文件
1 # polls/templates/polls/index.html 2 3 {% if latest_question_list %} 4 <ul> 5 {% for question in latest_question_list %} 6 <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> 7 {% endfor %} 8 </ul> 9 {% else %} 10 <p>No polls are available.</p> 11 {% endif %}
最后,修改polls/views.py文件
1 # polls/views.py 2 3 from django.http import HttpResponse 4 from django.template import RequestContext, loader 5 6 from .models import Question 7 8 9 def index(request): 10 latest_question_list = Question.objects.order_by(‘-pub_date‘)[:5] 11 template = loader.get_template(‘polls/index.html‘) 12 context = RequestContext(request, { 13 ‘latest_question_list‘: latest_question_list, 14 }) 15 return HttpResponse(template.render(context))
该代码加载polls/index.html,并将context传递给它。Context是映射模板变量到Python对象的字典。
render()方法可以简化代码
1 # polls/views.py 2 3 from django.shortcuts import render 4 5 from .models import Question 6 7 8 def index(request): 9 latest_question_list = Question.objects.order_by(‘-pub_date‘)[:5] 10 context = {‘latest_question_list‘: latest_question_list} 11 return render(request, ‘polls/index.html‘, context)
5. 抛出404错误
通过detail视图来示范实现
1 # polls/views.py 2 3 from django.http import Http404 4 from django.shortcuts import render 5 6 from .models import Question 7 # ... 8 def detail(request, question_id): 9 try: 10 question = Question.objects.get(pk=question_id) 11 except Question.DoesNotExist: 12 raise Http404("Question does not exist") 13 return render(request, ‘polls/detail.html‘, {‘question‘: question})
同时对polls/detail.html进行修改
1 # polls/templates/polls/detail.html 2 3 {{ question }}
使用get_object_or_404()进行代码简化
1 #polls/views.py 2 3 from django.shortcuts import get_object_or_404, render 4 5 from .models import Question 6 # ... 7 def detail(request, question_id): 8 question = get_object_or_404(Question, pk=question_id) 9 return render(request, ‘polls/detail.html‘, {‘question‘: question})
6. 使用模板系统
考虑context变量,对polls/detail.html进行修改
1 # polls/templates/polls/detail.html 2 3 <h1>{{ question.question_text }}</h1> 4 <ul> 5 {% for choice in question.choice_set.all %} 6 <li>{{ choice.choice_text }}</li> 7 {% endfor %} 8 </ul>
7. 移除模板中的硬编码URL
比如polls/index.html,原代码不利于修改:
1 <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
改进为:
1 <li><a href="{% url ‘detail‘ question.id %}">{{ question.question_text }}</a></li>
这样改进过后,对URL的修改会变得很容易,比如,把以下代码
1 ... 2 # the ‘name‘ value as called by the {% url %} template tag 3 url(r‘^(?P<question_id>[0-9]+)/$‘, views.detail, name=‘detail‘), 4 ...
改为
1 ... 2 # added the word ‘specifics‘ 3 url(r‘^specifics/(?P<question_id>[0-9]+)/$‘, views.detail, name=‘detail‘), 4 ...
8. URL命名空间
一个项目里往往有很多应用,如果两个应用都有叫做detail的视图,Django会怎么区分它们的URL名称呢?答案是mysite/urls.py中可以添加命名空间到URLconf。比如:
1 # mysite/urls.py 2 3 from django.conf.urls import include, url 4 from django.contrib import admin 5 6 urlpatterns = [ 7 url(r‘^polls/‘, include(‘polls.urls‘, namespace="polls")), 8 url(r‘^admin/‘, include(admin.site.urls)), 9 ]
同时将polls.index.html从
1 # polls/templates/polls/index.html 2 3 <li><a href="{% url ‘detail‘ question.id %}">{{ question.question_text }}</a></li>
修改为
1 # polls/templates/polls/index.html 2 3 <li><a href="{% url ‘polls:detail‘ question.id %}">{{ question.question_text }}</a></li>
--The End--