阅读:1757次   评论:0条   更新时间:2011-06-01    

Use generic views: Less code is better

使用通用视图:代码越少越好

 

The detail() (from Tutorial 3) and results() views are stupidly simple -- and, as mentioned above, redundant. The index() view (also from Tutorial 3), which displays a list of polls, is similar.

detail()results()都太简单了,而且代码上也有重复。显示投票列表的index()也有类似的问题。

 

These views represent a common case of basic Web development: getting data from the database according to a parameter passed in the URL, loading a template and returning the rendered template. Because this is so common, Django provides a shortcut, called the "generic views" system.

这些视图都代表了Web开发中的一类现象:根据URL中的参数从数据库中获取数据,加载模板并返回渲染后的内容。这类现象非常普遍,因此Django提供了快捷方法,称为“通用视图”。

 

Generic views abstract common patterns to the point where you don't even need to write Python code to write an app.

有了通用视图,你就不需要写任何Python代码来编写程序了。

 

Let's convert our poll app to use the generic views system, so we can delete a bunch of our own code. We'll just have to take a few steps to make the conversion.

现在用通用视图来修改投票程序,我们就可以删除掉一些代码了。下面只需要做几步就能完成修改。

 

Why the code-shuffle?

Generally, when writing a Django app, you'll evaluate whether generic views are a good fit for your problem, and you'll use them from the beginning, rather than refactoring your code halfway through. But this tutorial intentionally has focused on writing the views "the hard way" until now, to focus on core concepts.

You should know basic math before you start using a calculator.

为什么要梳理代码?

一般,编写Django程序时,你需要估计一下使用通用视图是否适合你的系统,如果适合,那从最开始就应该使用通用视图而不是开发了一半程序再来改代码。但是本文有意从一开始就介绍自行编写视图的方法,是为了让读者理解核心内容。

就好像你要使用计算机,至少应该知道基本的数学知识。

 

First, open the polls/urls.py URLconf. It looks like this, according to the tutorial so far:

首先,打开polls/urls.py。这里面的URLconf如下所示:

from django.conf.urls.defaults import *

 

urlpatterns = patterns('mysite.polls.views',

    (r'^$', 'index'),

    (r'^(?P<poll_id>\d+)/$', 'detail'),

    (r'^(?P<poll_id>\d+)/results/$', 'results'),

    (r'^(?P<poll_id>\d+)/vote/$', 'vote'),

)

 

Change it like so:

将代码改成下面的样子:

from django.conf.urls.defaults import *

from mysite.polls.models import Poll

 

info_dict = {

    'queryset': Poll.objects.all(),

}

 

urlpatterns = patterns('',

    (r'^$', 'django.views.generic.list_detail.object_list', info_dict),

    (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),

    url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'),

    (r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),

)

 

We're using two generic views here: object_list() and object_detail(). Respectively, those two views abstract the concepts of "display a list of objects" and "display a detail page for a particular type of object."

  • Each generic view needs to know what data it will be acting upon. This data is provided in a dictionary. The queryset key in this dictionary points to the list of objects to be manipulated by the generic view.
  • The object_detail() generic view expects the ID value captured from the URL to be called "object_id", so we've changed poll_id to object_id for the generic views.
  • We've added a name, poll_results, to the results view so that we have a way to refer to its URL later on (see the documentation about naming URL patterns for information). We're also using the url() function from django.conf.urls.defaults here. It's a good habit to use url() when you are providing a pattern name like this.

我们这里用了两个通用视图:object_list()object_detail()。这两个视图分别用于“展示纪录的列表”和“展示某个特定的记录”。

l         每个通用视图都要知道需要使用哪些数据。这些数据在一个字典里提供。字典中的queryset索引对应的数据就是视图中要操作的对象。

l         object_detail()通用视图需要一个从URL中捕获的ID值,名称限定为object_id。所以我们把poll_id改成了object_id

l         results视图里我们加上了一个poll_results参数,这样就能在后面引用它的URL了(请看naming URL patterns文档)。这里还要使用django.conf.urls.defaultsurl()函数。在刚才这样的情景下使用url()函数是个很好的习惯。

 

By default, the object_detail() generic view uses a template called <app name>/<model name>_detail.html. In our case, it'll use the template "polls/poll_detail.html". Thus, rename your polls/detail.html template to polls/poll_detail.html, and change the render_to_response() line in vote().

一般,object_detail()通用视图使用<app name>/<model name>_detail.html作为模板。这里,该视图会使用polls/poll_detail.html。所以,把polls/detail.html更名为polls/poll_detail.html,然后在vote()中修改render_to_response()这一行。

 

Similarly, the object_list() generic view uses a template called <app name>/<model name>_list.html. Thus, rename polls/index.html to polls/poll_list.html.

同样,object_list()通用视图使用<app name>/<model name>_list.html作为模板。所以,把polls/index.html更名为polls/poll_list.html

 

Because we have more than one entry in the URLconf that uses object_detail() for the polls app, we manually specify a template name for the results view: template_name='polls/results.html'. Otherwise, both views would use the same template. Note that we use dict() to return an altered dictionary in place.

由于在这个投票程序中的URLconf设置里,有多个纪录都用到了object_detail()视图,我们要人工给results视图指定模板名:template_name='polls/results.html'。否则,这些使用了同一个通用视图的URL就会加载同一个模板。注意这里我们用dict()来返回一个新的字典。

 

Note

django.db.models.QuerySet.all() is lazy

It might look a little frightening to see Poll.objects.all() being used in a detail view which only needs one Poll object, but don't worry; Poll.objects.all() is actually a special object called a QuerySet, which is "lazy" and doesn't hit your database until it absolutely has to. By the time the database query happens, the object_detail() generic view will have narrowed its scope down to a single object, so the eventual query will only select one row from the database.

If you'd like to know more about how that works, The Django database API documentation explains the lazy nature of QuerySet objects.

注意

django.db.models.QuerySet.all()是一个懒惰查询方法。

detail视图中只需要使用一条Poll纪录,而在这里使用Poll.objects.all()方法看起来让人觉得会影响性能。请别担心,Poll.objects.all()返回一个称为QuerySet的对象,实际上,这个对象只有在真正必要的时候才会去访问数据库。在查询数据库时,object_detail()视图会将范围缩减到单个纪录,所以只会从数据库返回被选中的纪录。

如果你想知道这其中到底是怎么工作的,Django 数据库API文档会告诉你QuerySet对象的懒惰特性

 

In previous parts of the tutorial, the templates have been provided with a context that contains the poll and latest_poll_list context variables. However, the generic views provide the variables object and object_list as context. Therefore, you need to change your templates to match the new context variables. Go through your templates, and modify any reference to latest_poll_list to object_list, and change any reference to poll to object.

在前面几部分中,模板内都传入了一个包含polllatest_poll_listcontext对象。但是通用视图提供objectobject_list作为context对象。所以,需要修改模板文件来适应新的context变量。在你的模板中,将所有latest_poll_list替换为object_list,所有poll替换为object

 

You can now delete the index(), detail() and results() views from polls/views.py. We don't need them anymore -- they have been replaced by generic views.

你现在可以从polls/views.py中删除index()detail()result()视图了。我们不再需要这些代码了——它们已经被通用函数代替。

 

The vote() view is still required. However, it must be modified to match the new context variables. In the render_to_response() call, rename the poll context variable to object.

vote()视图还是必要的,但是还是要修改一下变量名。在调用render_to_response()时,将poll重命名为object

 

The last thing to do is fix the URL handling to account for the use of generic views. In the vote view above, we used the reverse() function to avoid hard-coding our URLs. Now that we've switched to a generic view, we'll need to change the reverse() call to point back to our new generic view. We can't simply use the view function anymore -- generic views can be (and are) used multiple times -- but we can use the name we've given:

最后一件要做的事就是为了跳转到通用视图而修改一下URL的处理。在vote视图中,使用了reverse()来解决硬编码URL的问题。现在我们使用了通用视图,需要修改reverse()重新指向到通用视图。在reverse()中我们不能简单地再直接用视图的名称了——因为在URLconf中通用视图是可以多次使用的,这样就没办法分辨到底跳转到哪个URL——但是我们可以使用给定的名称:

return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))

 

Run the server, and use your new polling app based on generic views.

重新启动测试服务器,看看这个使用了通用视图的全新程序。

 

For full details on generic views, see the generic views documentation.

要了解更多通用视图的内容,请参考通用视图文档

 

Coming soon

敬请期待

 

The tutorial ends here for the time being. Future installments of the tutorial will cover:

  • Advanced form processing
  • Using the RSS framework
  • Using the cache framework
  • Using the comments framework
  • Advanced admin features: Permissions
  • Advanced admin features: Custom JavaScript

由于时间关系,新手入门的文章就只能到这里了。将来的文档里会加入下面的内容:

l         高级表单处理

l         使用RSS组件

l         使用缓存组件

l         使用评论组件

l         高级管理后台特性:权限

l         高级管理后台特性:自定义的JavaScript

 

In the meantime, you might want to check out some pointers on where to go from here

与此同时,你可能想知道接下来应该做些什么

评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

文章信息

Global site tag (gtag.js) - Google Analytics