[译]Django first steps Part3

2 编写更多的view

修改polls/views.py文件:

from django.shortcuts 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(response % question_id)

def vote(request,question_id):
    return HttpResponse("You're voting on question %s." % question_id)

修改polls/urls.py文件:

from django.conf.urls import url
from . import views

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/34/ 将运行detail() ,当有人请求页面的时候,说“/polls/34/ ”,django将会加载“mysite.urls ”,因为在settings里面的“ROOT_URLCONF”的设置。它会按顺序找到“urlpatterns ”参数对应的正则表达式匹配的url,首先匹配到’^polls/’, 然后到‘polls.urls’中匹配到"34/" – r’^(?P<question_id>[0-9]+)/$’, 并将url中的参数映射给 detail() view:

detail(request=<HttpRequest object>, question_id='34')

(?P<question_id>[0-9]+)中的question_id将作为参数传给view中的函数,[0-9]+表示一个或多个数字。当然,也可以直接使用html来作为url,如下:

url(r'^polls/latest\.html$', views.index), 

但是,不要这么弄,这样太傻了。

3 写view到底干了啥

每一个view负责做下面两件事情中的一件:

  • 返回一个包含内容的HttpResponse 对象

  • 返回一个例外,如http404

你的view能够读取数据库中的记录,能够使用django的template系统或第三方模板系统,能够生成一个pdf文件,输出xml,创建一个zip文件,通过使用python的库得到你所想要的任何东西。

django需要的只是HttpResponse 对象,现在我们来修改一下part2中的index(),用来列举最近的5个问题。

#_*_coding:utf-8_*_
from django.shortcuts import HttpResponse
from . import models

def index(request):
    #倒排所有的question问题,只取前五个
    latest_question_list = models.Question.objects.order_by("-pub_date")[:5]
    #合并列表,中间用","隔开
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

但是有一个问题:view使用硬编码(hard-coded)方式编写,如果你想要修改页面就需要修改python代码,所以django使用template模板系统来显示页面。

首先创建一templates的目录在polls下面,django会在这里边找模板,你的工程中TEMPLATES 设置描述了django如何加载和渲染模板, describes how Django will load and render templates. 默认设置一个 DjangoTemplates backend 中 APP_DIRS 为True. DjangoTemplates 将会在每个INSTALLED_APPS中寻找 “templates” 。

在template下再创建一个polls的文件夹,以后可以通过polls/index.html来访问模板文件。

Template的命名

我们可以将所有的html文件都放置在一起,但是不方便。如果不同的app有相同的模板文件,django是不能分辨他们的,一个比较好的办法是将不同的模板放置在以app命名的文件夹中。

修改 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 %}
...

修改views文件

#_*_coding:utf-8_*_
from django.shortcuts import HttpResponse
from . import models
from django.template import loader

def index(request):
    #倒排所有的question问题,只取前五个
    latest_question_list = models.Question.objects.order_by("-pub_date")[:5]
    #得到一个模板
    temp = loader.get_template('polls/index.html')
    #需要传入的内容,一个字典
    context = {
        "latest_qiestion_list":latest_question_list,
    }
    #返回
    return HttpResponse(temp.render(context,request))
...

A shortcut: render()

加载和渲染模板是非常频繁的工作,如果每次使用HttpResponse来返回,比较麻黄,因此django提供了一个叫做render()的捷径:

#_*_coding:utf-8_*_
from django.shortcuts import HttpResponse,render
from . import models

def index(request):
    #倒排所有的question问题,只取前五个
    latest_question_list = models.Question.objects.order_by("-pub_date")[:5]
    #返回
    return render(request,"polls/index.html",{
        "latest_question_list":latest_question_list,
    })
...

这样就不用导入loader了。render() 函数的第一个参数是request,第二个参数是模板,第三个参数是一个字典,用于模板传入参数使用, 返回一个给定内容和渲染模板的 HttpResponse 对象。

4 Raising a 404 error

下面来处理下detail视图,显示问题内容,修改polls/views.py文件:

...
def detail(request,question_id):
    try:
        question = models.Question.objects.get(pk=question_id)
    except models.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()

我们经常get一个对象数据,如果不存在就产生一个HTTP404,django提供了一个快捷方式:

...
def detail(request,question_id):
    question = get_object_or_404(models.Question,pk=question_id)
    return render(request,"polls/detail.html",{
        "question":question
    })
...

Philosophy :

为什么我们使用get_object_or_404() 或者Http404 来代替ObjectDoesNotExist 呢?

因为我们需要联系models层和views层,django的一个重要设计理念就是维持松耦合,一些controlled 耦合 在django.shortcuts模块中介绍。

还有一个get_list_or_404() 函数,对应的filter(),而get_object_or_404() 对应的是get()。

5 使用模板系统(template)

回到detail()视图,我们修改一下detail.html文件:

<h1>
    {{ question.question_text }}
</h1>
<ul>
{#question.choice_set.all:全部choice#}
{% for choice in question.choice_set.all %}
{#    显示choice的内容:#}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

通过“.”来获取question表对应的列,如question.question_text获取了question的内容;同样也能使用for进行循环,注意格式。

6 删除模板中url的硬编码

还记得index.html中的:

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> 

我们给他改成:

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

其实他是通过一个{% url %} 的template tag来实现调用的,详细请参考tempalte tag。

那么如果哪天我需要修改url的时候,如:

url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'), 

就不需要再调整模板中的index.html文件。

7 url的命名

在我们的例子中只有一个app就是polls,但是在真实的django中,我们会有五个、十个甚至更多的app,怎么区分它们的url名字呢?比如说bolg和polls都有detail视图,那么使用{% url %}如何区分不同的app,方法就是在url文件中增加一行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"),
]

原来调用的时候:

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> 

现在这样:polls:detail

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> 

未完待续。

posted @ 2016-06-05 21:02  felo  阅读(235)  评论(0编辑  收藏  举报