用Python的Django框架来制作一个RSS阅读器


Posted in Python onJuly 22, 2015

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:

  1.     LatestEntries``表示的内容将对应到``feeds/latest/ .
  2.     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 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 <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/latest_title.html 和 feeds/latest_description.html ,后者是URLConf里为对应feed指定的 slug 。注意 .html 后缀是必须的。 Note that the .html extension is required.

    RSS系统模板渲染每一个条目,需要给传递2个参数给模板上下文变量:

  1.         obj : 当前对象 ( 返回到 items() 任意对象之一 )。
  2.         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 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/) 。
指定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类型如表所示。

用Python的Django框架来制作一个RSS阅读器

闭包

为了指定闭包(例如,与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}),
  # ...
)

Python 相关文章推荐
理解Python中的With语句
Feb 02 Python
python之PyMongo使用总结
May 26 Python
Python操作SQLite数据库的方法详解
Jun 16 Python
Python实现比较扑克牌大小程序代码示例
Dec 06 Python
python将每个单词按空格分开并保存到文件中
Mar 19 Python
Python GUI编程 文本弹窗的实例
Jun 11 Python
Django 开发调试工具 Django-debug-toolbar使用详解
Jul 23 Python
django admin.py 外键,反向查询的实例
Jul 26 Python
如何基于python操作json文件获取内容
Dec 24 Python
Python如何安装第三方模块
May 28 Python
基于opencv的selenium滑动验证码的实现
Jul 24 Python
python 使用Tensorflow训练BP神经网络实现鸢尾花分类
May 12 Python
利用Python的Django框架生成PDF文件的教程
Jul 22 #Python
在Python的Django框架中生成CSV文件的方法
Jul 22 #Python
在主机商的共享服务器上部署Django站点的方法
Jul 22 #Python
在Lighttpd服务器中运行Django应用的方法
Jul 22 #Python
简单的Apache+FastCGI+Django配置指南
Jul 22 #Python
使用FastCGI部署Python的Django应用的教程
Jul 22 #Python
使用相同的Apache实例来运行Django和Media文件
Jul 22 #Python
You might like
如何使用PHP实现javascript的escape和unescape函数
2013/06/29 PHP
PHP中上传多个文件的表单设计例子
2014/11/19 PHP
PHP 文件上传限制问题
2019/09/01 PHP
Nigma vs Alliance BO5 第三场2.14
2021/03/10 DOTA
非常不错的功能强大代码简单的管理菜单美化版
2008/07/09 Javascript
JavaScript入门教程(10) 认识其他对象
2009/01/31 Javascript
优化innerHTML操作(提高代码执行效率)
2011/08/20 Javascript
js+div实现图片滚动效果代码
2014/02/10 Javascript
详解Node.js access_token的获取、存储及更新
2017/06/20 Javascript
Vue+Java+Base64实现条码解析的示例
2020/09/23 Javascript
详解JavaScript之Array.reduce源码解读
2020/11/01 Javascript
使用python装饰器验证配置文件示例
2014/02/24 Python
Python中encode()方法的使用简介
2015/05/18 Python
Python写入数据到MP3文件中的方法
2015/07/10 Python
详解Django框架中用户的登录和退出的实现
2015/07/23 Python
python实现给数组按片赋值的方法
2015/07/28 Python
python 默认参数问题的陷阱
2016/02/29 Python
Python实现购物系统(示例讲解)
2017/09/13 Python
使用实现pandas读取csv文件指定的前几行
2018/04/20 Python
python 读取txt中每行数据,并且保存到excel中的实例
2018/04/29 Python
Python基于scipy实现信号滤波功能
2019/05/08 Python
弄懂这56个Python使用技巧(轻松掌握Python高效开发)
2019/09/18 Python
python脚本和网页有何区别
2020/07/02 Python
Python使用shutil模块实现文件拷贝
2020/07/31 Python
CSS3属性选择符介绍
2008/10/17 HTML / CSS
CSS3 文字动画效果
2020/11/12 HTML / CSS
太阳镜仓库,售价20美元或更少:Sunglass Warehouse
2016/09/28 全球购物
Lulu & Georgia官方网站:购买地毯、家具、抱枕、壁纸、床上用品等
2018/03/19 全球购物
Hanro官网:奢华男士和女士内衣、睡衣和家居服
2018/10/25 全球购物
英国时尚泳装品牌:Maru Swimwear
2019/10/06 全球购物
解释DataSet(ds) 和 ds as DataSet 的含义
2014/07/27 面试题
师范院校学生自荐信范文
2013/12/27 职场文书
打造高效课堂实施方案
2014/03/22 职场文书
法定代表人授权委托书范文
2014/09/22 职场文书
SQL Server2019数据库之简单子查询的具有方法
2021/04/27 SQL Server
Python简易开发之制作计算器
2022/04/28 Python