内容聚合器应用框架
Django带来了一个高级的聚合生成框架,它使得创建RSS和Atom feeds变得非常容易。
什么是RSS? 什么是Atom?
RSS和Atom都是基于XML的格式,你可以用它来提供有关你站点内容的自动更新的feed。 了解更多关于RSS的可以访问 http://www.whatisrss.com/, 更多Atom的信息可以访问 http://www.atomenabled.org/.
想创建一个联合供稿的源(syndication feed),所需要做的只是写一个简短的python类。 你可以创建任意多的源(feed)。
高级feed生成框架是一个默认绑定到/feeds/的视图,Django使用URL的其它部分(在/feeds/之后的任何东西)来决定输出 哪个feed Django uses the remainder of the URL (everything after /feeds/
) to determine which feed to return.
要创建一个 sitemap,你只需要写一个 Sitemap
类然后配置你的URLconf指向它。
初始化
为了在您的Django站点中激活syndication feeds, 添加如下的 URLconf:
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}
),
这一行告诉Django使用RSS框架处理所有的以 "feeds/"
开头的URL. ( 你可以修改 "feeds/"
前缀以满足您自己的要求. )
URLConf里有一行参数: {'feed_dict': feeds}
,这个参数可以把对应URL需要发布的feed内容传递给 syndication framework
特别的,feed_dict应该是一个映射feed的slug(简短URL标签)到它的Feed类的字典 你可以在URL配置本身里定义feed_dict,这里是一个完整的例子 You can define the feed_dict
in the URLconf itself. Here’s a full example URLconf:
from django.conf.urls.defaults import *
from mysite.feeds import LatestEntries, LatestEntriesByCategory
feeds = {
'latest': LatestEntries,
'categories': LatestEntriesByCategory,
}
urlpatterns = patterns('',
# ...
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}),
# ...
)
前面的例子注册了两个feed:
LatestEntries
.表示的内容将对应到
feeds/latest/LatestEntriesByCategory
.的内容将对应到
feeds/categories/
以上的设定完成之后,接下来需要自己定义 Feed
类
一个 Feed
类是一个简单的python类,用来表示一个syndication feed. 一个feed可能是简单的 (例如一个站点新闻feed,或者最基本的,显示一个blog的最新条目),也可能更加复杂(例如一个显示blog某一类别下所有条目的feed。 这里类别 category 是个变量).
Feed类必须继承django.contrib.syndication.feeds.Feed,它们可以在你的代码树的任何位置
一个简单的Feed
This simple example describes a feed of the latest five blog entries for a given blog:
from django.contrib.syndication.feeds import Feed
from mysite.blog.models import Entry
class LatestEntries(Feed):
title = "My Blog"
link = "/archive/"
description = "The latest news about stuff."
def items(self):
return Entry.objects.order_by('-pub_date')[:5]
要注意的重要的事情如下所示:
子类
django.contrib.syndication.feeds.Feed
.title
,link
, 和description
对应一个标准 RSS 里的<title>
,<link>
, 和<description>
标签.items()
是一个方法,返回一个用以包含在包含在feed的<item>
元素里的 list 虽然例子里用Djangos database API返回的NewsItem
对象,items()
不一定必须返回 model的实例 Although this example returnsEntry
objects using Django’s database API,items()
doesn’t have to return model instances.
还有一个步骤,在一个RSS feed里,每个(item)有一个(title),(link)和(description),我们需要告诉框架 把数据放到这些元素中 In an RSS feed, each <item>
has a <title>
, <link>
, and <description>
. We need to tell the framework what data to put into those elements.
如果要指定<title>
和<description>
,可以建立一个Django模板(见Chapter 4)名字叫feeds/latesttitle.html
和feeds/latestdescription.html
,后者是URLConf里为对应feed指定的slug
。注意.html
后缀是必须的。 Note that the.html
extension is required.RSS系统模板渲染每一个条目,需要给传递2个参数给模板上下文变量:-obj
: 当前对象 ( 返回到items()
任意对象之一 )。-site
: 一个表示当前站点的django.models.core.sites.Site
对象。 这对于{{ site.domain }}
或者{{ site.name }}
很有用。如果你在创建模板的时候,没有指明标题或者描述信息,框架会默认使用"{{ obj }}"
,对象的字符串表示。 (For model objects, this will be the__unicode
()
method.你也可以通过修改Feed
类中的两个属性title_template
和description_template
来改变这两个模板的名字。你有两种方法来指定<link>
的内容。 Django 首先执行items()
中每一项的get_absolute_url()
方法。 如果该方法不存在,就会尝试执行Feed
类中的item_link()
方法,并将自身作为item
参数传递进去。get_absolute_url()
和item_link()
都应该以Python字符串形式返回URL。对于前面提到的LatestEntries
例子,我们可以实现一个简单的feed模板。latest_title.html
包括:
{{ obj.title }}
并且latest_description.html
包含:
{{ obj.description }}
这真是 太 简单了!
一个更复杂的Feed
框架通过参数支持更加复杂的feeds。
For example, say your blog offers an RSS feed for every distinct tag you’ve used to categorize your entries. 如果为每一个单独的区域建立一个 Feed
类就显得很不明智。
取而代之的方法是,使用聚合框架来产生一个通用的源,使其可以根据feeds URL返回相应的信息。
Your tag-specific feeds could use URLs like this:
http://example.com/feeds/tags/python/
: Returns recent entries tagged with pythonhttp://example.com/feeds/tags/cats/
: Returns recent entries tagged with cats
固定的那一部分是 "beats"
(区域)。
举个例子会澄清一切。 下面是每个地区特定的feeds:
from django.core.exceptions import ObjectDoesNotExist
from mysite.blog.models import Entry, Tag
class TagFeed(Feed):
def get_object(self, bits):
# In case of "/feeds/tags/cats/dogs/mice/", or other such
# clutter, check that bits has only one member.
if len(bits) != 1:
raise ObjectDoesNotExist
return Tag.objects.get(tag=bits[0])
def title(self, obj):
return "My Blog: Entries tagged with %s" % obj.tag
def link(self, obj):
return obj.get_absolute_url()
def description(self, obj):
return "Entries tagged with %s" % obj.tag
def items(self, obj):
entries = Entry.objects.filter(tags__id__exact=obj.id)
return entries.order_by('-pub_date')[:30]
以下是RSS框架的基本算法,我们假设通过URL /rss/beats/0613/
来访问这个类:
框架获得了URL/rss/beats/0613/
并且注意到URL中的slug部分后面含有更多的信息。 它将斜杠("/"
)作为分隔符,把剩余的字符串分割开作为参数,调用Feed
类的getobject()
方法。在这个例子中,添加的信息是['0613']
。对于/rss/beats/0613/foo/bar/
的一个URL请求, 这些信息就是['0613', 'foo', 'bar']
。get_object()
就根据给定的bits
值来返回区域信息。In this case, it uses the Django database API to retrieve theTag
. Note thatget_object()
should raisedjango.core.exceptions.ObjectDoesNotExist
if given invalid parameters. 在Beat.objects.get()
调用中也没有出现try
/except
代码块。 函数在出错时抛出Beat.DoesNotExist
异常,而Beat.DoesNotExist
是ObjectDoesNotExist
异常的一个子类型。为产生<title>
,<link>
, 和<description>
的feeds, Django使用title()
,link()
, 和description()
方法。 在上面的例子中,它们都是简单的字符串类型的类属性,而这个例子表明,它们既可以是字符串, 也可以是_ 方法。 对于每一个title
,link
和description
的组合,Django使用以下的算法:- 试图调用一个函数,并且以get_object()
返回的对象作为参数传递给obj
参数。- 如果没有成功,则不带参数调用一个方法。- 还不成功,则使用类属性。最后,值得注意的是,这个例子中的items()
使用obj
参数。 对于items
的算法就如同上面第一步所描述的那样,首先尝试items(obj)
, 然后是items()
,最后是items
类属性(必须是一个列表)。
Feed
类所有方法和属性的完整文档,请参考官方的Django文档 (http://www.djangoproject.com/documentation/0.96/syndication_feeds/) 。
指定Feed的类型
默认情况下, 聚合框架生成RSS 2.0. 要改变这样的情况, 在 Feed
类中添加一个 feed_type
属性. To change that, add a feed_type
attribute to your Feed
class:
from django.utils.feedgenerator import Atom1Feed
class MyFeed(Feed):
feed_type = Atom1Feed
注意你把 feed_type
赋值成一个类对象,而不是类实例。 目前合法的Feed类型如表11-1所示。
Feed 类 | 类型 |
---|---|
django.utils.feedgenerator.Rss201rev2Feed | RSS 2.01 (default) |
django.utils.feedgenerator.RssUserland091Feed | RSS 0.91 |
django.utils.feedgenerator.Atom1Feed | Atom 1.0 |
闭包
为了指定闭包(例如,与feed项比方说MP3 feeds相关联的媒体资源信息),使用 item_enclosure_url
, item_enclosure_length
, 以及 item_enclosure_mime_type
,比如
from myproject.models import Song
class MyFeedWithEnclosures(Feed):
title = "Example feed with enclosures"
link = "/feeds/example-with-enclosures/"
def items(self):
return Song.objects.all()[:30]
def item_enclosure_url(self, item):
return item.song_url
def item_enclosure_length(self, item):
return item.song_length
item_enclosure_mime_type = "audio/mpeg"
当然,你首先要创建一个包含有 song_url
和 song_length
(比如按照字节计算的长度)域的 Song
对象。
语言
聚合框架自动创建的Feed包含适当的 <language>
标签(RSS 2.0) 或 xml:lang
属性(Atom). 他直接来自于您的 LANGUAGE_CODE
设置. This comes directly from your LANGUAGE_CODE
setting.
URLs
link
方法/属性可以以绝对URL的形式(例如, "/blog/"
)或者指定协议和域名的URL的形式返回(例如 "http://www.example.com/blog/"
)。如果 link
没有返回域名,聚合框架会根据 SITE_ID
设置,自动的插入当前站点的域信息。 (See Chapter 16 for more on SITE_ID
and the sites framework.)
Atom feeds需要 <link rel="self">
指明feeds现在的位置。 The syndication framework populates this automatically.
同时发布Atom and RSS
一些开发人员想 同时 支持Atom和RSS。 这在Django中很容易实现: 只需创建一个你的 feed
类的子类,然后修改 feed_type
,并且更新URLconf内容。 下面是一个完整的例子: Here’s a full example:
from django.contrib.syndication.feeds import Feed
from django.utils.feedgenerator import Atom1Feed
from mysite.blog.models import Entry
class RssLatestEntries(Feed):
title = "My Blog"
link = "/archive/"
description = "The latest news about stuff."
def items(self):
return Entry.objects.order_by('-pub_date')[:5]
class AtomLatestEntries(RssLatestEntries):
feed_type = Atom1Feed
这是与之相对应那个的URLconf:
from django.conf.urls.defaults import *
from myproject.feeds import RssLatestEntries, AtomLatestEntries
feeds = {
'rss': RssLatestEntries,
'atom': AtomLatestEntries,
}
urlpatterns = patterns('',
# ...
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}),
# ...
)