用python的django框架来制作一个rss阅读器

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.*)/$’, ‘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.*)/$’, ‘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 里的 , , 和 标签.
items() 是一个方法,返回一个用以包含在包含在feed的 元素里的 list 虽然例子里用djangos database api返回的 newsitem 对象, items() 不一定必须返回 model的实例 although this example returns entry 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 has a , , and . we need to tell the framework what data to put into those elements.

如果要指定 和 ,可以建立一个django模板(见chapter 4)名字叫 feeds/latest_title.html 和 feeds/latest_description.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 来改变这两个模板的名字。

你有两种方法来指定 的内容。 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 python

http://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 类的 get_object() 方法。

在这个例子中,添加的信息是 [‘0613’] 。对于 /rss/beats/0613/foo/bar/ 的一个url请求, 这些信息就是 [‘0613’, ‘foo’, ‘bar’] 。

get_object() 就根据给定的 bits 值来返回区域信息。

in this case, it uses the django database api to retrieve the tag . note that get_object() should raise django.core.exceptions.objectdoesnotexist if given invalid parameters. 在 beat.objects.get() 调用中也没有出现 try /except 代码块。 函数在出错时抛出 beat.doesnotexist 异常,而 beat.doesnotexist 是 objectdoesnotexist 异常的一个子类型。

为产生 , , 和 的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类型如表所示。

2015722150842180.jpg (705×179)

闭包

为了指定闭包(例如,与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包含适当的 标签(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需要 指明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.*)/$’, ‘django.contrib.syndication.views.feed’,
{‘feed_dict’: feeds}),
# …
)

Posted in 未分类

发表评论