用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<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>.*)/$',{'feed_dict': feeds}),# ... ) 前面的例子注册了两个feed:
以上的设定完成之后,接下来需要自己定义 Feed 类 一个 Feed 类是一个简单的python类,用来表示一个syndication feed. 一个feed可能是简单的 (例如一个站点新闻feed,或者最基本的,显示一个blog的最新条目),也可能更加复杂(例如一个显示blog某一类别下所有条目的feed。 这里类别 category 是个变量). Feed类必须继承django.contrib.syndication.feeds.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] 要注意的重要的事情如下所示:
还有一个步骤,在一个RSS feed里,每个(item)有一个(title),(link)和(description),我们需要告诉框架 把数据放到这些元素中 In an RSS feed,each <item> has a <title>,and <description> . We need to tell the framework what data to put into those elements. 如果要指定 <title> 和 <description> ,可以建立一个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 }}" ,对象的字符串表示。 (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 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 异常的一个子类型。 为产生 <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/) 。 默认情况下,聚合框架生成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类型如表所示。 闭包 为了指定闭包(例如,与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. 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和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,# ... )
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |