用Python的Django框架來(lái)制作一個(gè)RSS閱讀器
Django帶來(lái)了一個(gè)高級(jí)的聚合生成框架,它使得創(chuàng)建RSS和Atom feeds變得非常容易。
什么是RSS? 什么是Atom?
RSS和Atom都是基于XML的格式,你可以用它來(lái)提供有關(guān)你站點(diǎn)內(nèi)容的自動(dòng)更新的feed。 了解更多關(guān)于RSS的可以訪問(wèn) http://www.whatisrss.com/, 更多Atom的信息可以訪問(wèn) http://www.atomenabled.org/.
想創(chuàng)建一個(gè)聯(lián)合供稿的源(syndication feed),所需要做的只是寫一個(gè)簡(jiǎn)短的python類。 你可以創(chuàng)建任意多的源(feed)。
高級(jí)feed生成框架是一個(gè)默認(rèn)綁定到/feeds/的視圖,Django使用URL的其它部分(在/feeds/之后的任何東西)來(lái)決定輸出 哪個(gè)feed Django uses the remainder of the URL (everything after /feeds/ ) to determine which feed to return.
要?jiǎng)?chuàng)建一個(gè) sitemap,你只需要寫一個(gè) Sitemap 類然后配置你的URLconf指向它。
初始化
為了在您的Django站點(diǎn)中激活syndication feeds, 添加如下的 URLconf:
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds} ),
這一行告訴Django使用RSS框架處理所有的以 "feeds/" 開頭的URL. ( 你可以修改 "feeds/" 前綴以滿足您自己的要求. )
URLConf里有一行參數(shù): {'feed_dict': feeds},這個(gè)參數(shù)可以把對(duì)應(yīng)URL需要發(fā)布的feed內(nèi)容傳遞給 syndication framework
特別的,feed_dict應(yīng)該是一個(gè)映射feed的slug(簡(jiǎn)短URL標(biāo)簽)到它的Feed類的字典 你可以在URL配置本身里定義feed_dict,這里是一個(gè)完整的例子 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}), # ... )
前面的例子注冊(cè)了兩個(gè)feed:
- LatestEntries``表示的內(nèi)容將對(duì)應(yīng)到``feeds/latest/ .
- LatestEntriesByCategory``的內(nèi)容將對(duì)應(yīng)到 ``feeds/categories/ .
以上的設(shè)定完成之后,接下來(lái)需要自己定義 Feed 類
一個(gè) Feed 類是一個(gè)簡(jiǎn)單的python類,用來(lái)表示一個(gè)syndication feed. 一個(gè)feed可能是簡(jiǎn)單的 (例如一個(gè)站點(diǎn)新聞feed,或者最基本的,顯示一個(gè)blog的最新條目),也可能更加復(fù)雜(例如一個(gè)顯示blog某一類別下所有條目的feed。 這里類別 category 是個(gè)變量).
Feed類必須繼承django.contrib.syndication.feeds.Feed,它們可以在你的代碼樹的任何位置
一個(gè)簡(jiǎn)單的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 對(duì)應(yīng)一個(gè)標(biāo)準(zhǔn) RSS 里的 <title> , <link> , 和 <description> 標(biāo)簽.
- items() 是一個(gè)方法,返回一個(gè)用以包含在包含在feed的 <item> 元素里的 list 雖然例子里用Djangos database API返回的 NewsItem 對(duì)象, items() 不一定必須返回 model的實(shí)例 Although this example returns Entry objects using Django's database API, items() doesn't have to return model instances.
還有一個(gè)步驟,在一個(gè)RSS feed里,每個(gè)(item)有一個(gè)(title),(link)和(description),我們需要告訴框架 把數(shù)據(jù)放到這些元素中 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> ,可以建立一個(gè)Django模板(見Chapter 4)名字叫 feeds/latest_title.html 和 feeds/latest_description.html ,后者是URLConf里為對(duì)應(yīng)feed指定的 slug 。注意 .html 后綴是必須的。 Note that the .html extension is required.
RSS系統(tǒng)模板渲染每一個(gè)條目,需要給傳遞2個(gè)參數(shù)給模板上下文變量:
- obj : 當(dāng)前對(duì)象 ( 返回到 items() 任意對(duì)象之一 )。
- site : 一個(gè)表示當(dāng)前站點(diǎn)的 django.models.core.sites.Site 對(duì)象。 這對(duì)于 {{ site.domain }} 或者 {{ site.name }} 很有用。
如果你在創(chuàng)建模板的時(shí)候,沒(méi)有指明標(biāo)題或者描述信息,框架會(huì)默認(rèn)使用 "{{ obj }}" ,對(duì)象的字符串表示。 (For model objects, this will be the __unicode__() method.
你也可以通過(guò)修改 Feed 類中的兩個(gè)屬性 title_template 和 description_template 來(lái)改變這兩個(gè)模板的名字。
你有兩種方法來(lái)指定 <link> 的內(nèi)容。 Django 首先執(zhí)行 items() 中每一項(xiàng)的 get_absolute_url() 方法。 如果該方法不存在,就會(huì)嘗試執(zhí)行 Feed 類中的 item_link() 方法,并將自身作為 item 參數(shù)傳遞進(jìn)去。
get_absolute_url() 和 item_link() 都應(yīng)該以Python字符串形式返回URL。
對(duì)于前面提到的 LatestEntries 例子,我們可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的feed模板。 latest_title.html 包括:
{{ obj.title }}
并且 latest_description.html 包含:
{{ obj.description }}
這真是 太 簡(jiǎn)單了!
一個(gè)更復(fù)雜的Feed
框架通過(guò)參數(shù)支持更加復(fù)雜的feeds。
For example, say your blog offers an RSS feed for every distinct tag you've used to categorize your entries. 如果為每一個(gè)單獨(dú)的區(qū)域建立一個(gè) Feed 類就顯得很不明智。
取而代之的方法是,使用聚合框架來(lái)產(chǎn)生一個(gè)通用的源,使其可以根據(jù)feeds URL返回相應(yīng)的信息。
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" (區(qū)域)。
舉個(gè)例子會(huì)澄清一切。 下面是每個(gè)地區(qū)特定的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框架的基本算法,我們假設(shè)通過(guò)URL /rss/beats/0613/ 來(lái)訪問(wèn)這個(gè)類:
框架獲得了URL /rss/beats/0613/ 并且注意到URL中的slug部分后面含有更多的信息。 它將斜杠("/" )作為分隔符,把剩余的字符串分割開作為參數(shù),調(diào)用 Feed 類的 get_object() 方法。
在這個(gè)例子中,添加的信息是 ['0613'] 。對(duì)于 /rss/beats/0613/foo/bar/ 的一個(gè)URL請(qǐng)求, 這些信息就是 ['0613', 'foo', 'bar'] 。
get_object() 就根據(jù)給定的 bits 值來(lái)返回區(qū)域信息。
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() 調(diào)用中也沒(méi)有出現(xiàn) try /except 代碼塊。 函數(shù)在出錯(cuò)時(shí)拋出 Beat.DoesNotExist 異常,而 Beat.DoesNotExist 是 ObjectDoesNotExist 異常的一個(gè)子類型。
為產(chǎn)生 <title> , <link> , 和 <description> 的feeds, Django使用 title() , link() , 和 description() 方法。 在上面的例子中,它們都是簡(jiǎn)單的字符串類型的類屬性,而這個(gè)例子表明,它們既可以是字符串, 也可以是 方法。 對(duì)于每一個(gè) title , link 和 description 的組合,Django使用以下的算法:
試圖調(diào)用一個(gè)函數(shù),并且以 get_object() 返回的對(duì)象作為參數(shù)傳遞給 obj 參數(shù)。
如果沒(méi)有成功,則不帶參數(shù)調(diào)用一個(gè)方法。
還不成功,則使用類屬性。
最后,值得注意的是,這個(gè)例子中的 items() 使用 obj 參數(shù)。 對(duì)于 items 的算法就如同上面第一步所描述的那樣,首先嘗試 items(obj) , 然后是 items() ,最后是 items 類屬性(必須是一個(gè)列表)。
Feed 類所有方法和屬性的完整文檔,請(qǐng)參考官方的Django文檔 (http://www.djangoproject.com/documentation/0.96/syndication_feeds/) 。
指定Feed的類型
默認(rèn)情況下, 聚合框架生成RSS 2.0. 要改變這樣的情況, 在 Feed 類中添加一個(gè) 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 賦值成一個(gè)類對(duì)象,而不是類實(shí)例。 目前合法的Feed類型如表所示。
閉包
為了指定閉包(例如,與feed項(xiàng)比方說(shuō)MP3 feeds相關(guān)聯(lián)的媒體資源信息),使用 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"
當(dāng)然,你首先要?jiǎng)?chuàng)建一個(gè)包含有 song_url 和 song_length (比如按照字節(jié)計(jì)算的長(zhǎng)度)域的 Song 對(duì)象。
語(yǔ)言
聚合框架自動(dòng)創(chuàng)建的Feed包含適當(dāng)?shù)?<language> 標(biāo)簽(RSS 2.0) 或 xml:lang 屬性(Atom). 他直接來(lái)自于您的 LANGUAGE_CODE 設(shè)置. This comes directly from your LANGUAGE_CODE setting.
URLs
link 方法/屬性可以以絕對(duì)URL的形式(例如, "/blog/" )或者指定協(xié)議和域名的URL的形式返回(例如 "http://www.example.com/blog/" )。如果 link 沒(méi)有返回域名,聚合框架會(huì)根據(jù) SITE_ID 設(shè)置,自動(dòng)的插入當(dāng)前站點(diǎn)的域信息。 (See Chapter 16 for more on SITE_ID and the sites framework.)
Atom feeds需要 <link rel="self"> 指明feeds現(xiàn)在的位置。 The syndication framework populates this automatically.
同時(shí)發(fā)布Atom and RSS
一些開發(fā)人員想 同時(shí) 支持Atom和RSS。 這在Django中很容易實(shí)現(xiàn): 只需創(chuàng)建一個(gè)你的 feed 類的子類,然后修改 feed_type ,并且更新URLconf內(nèi)容。 下面是一個(gè)完整的例子: 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
這是與之相對(duì)應(yīng)那個(gè)的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}), # ... )
相關(guān)文章
解決pycharm安裝后代碼區(qū)不能編輯的問(wèn)題
今天小編就為大家分享一篇解決pycharm安裝后代碼區(qū)不能編輯的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10Python利用reportlab實(shí)現(xiàn)制作pdf報(bào)告
這篇文章主要為大家詳細(xì)介紹了reportlab生成流文件格式、reportlab分頁(yè)和圖片流文件寫入reportlab等內(nèi)容,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12python爬蟲利器之requests庫(kù)的用法(超全面的爬取網(wǎng)頁(yè)案例)
這篇文章主要介紹了python爬蟲利器之requests庫(kù)的用法(超全面的爬取網(wǎng)頁(yè)案例),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Python用戶推薦系統(tǒng)曼哈頓算法實(shí)現(xiàn)完整代碼
這篇文章主要介紹了Python用戶推薦系統(tǒng)曼哈頓算法實(shí)現(xiàn)完整代碼,簡(jiǎn)單介紹了曼哈頓距離的定義,然后分享了其Python實(shí)現(xiàn)代碼,具有一定借鑒價(jià)值,需要的朋友可以了解下。2017-12-12Python 中的字符串基礎(chǔ)與應(yīng)用小結(jié)
在Python中,字符串可以用單引號(hào)或雙引號(hào)括起來(lái),'hello' 與 "hello" 是相同的,這篇文章主要介紹了Python 中的字符串基礎(chǔ)與應(yīng)用,需要的朋友可以參考下2023-09-09Python selenium實(shí)現(xiàn)斷言3種方法解析
這篇文章主要介紹了Python selenium實(shí)現(xiàn)斷言3種方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09python3 下載網(wǎng)絡(luò)圖片代碼實(shí)例
這篇文章主要介紹了python3 下載網(wǎng)絡(luò)圖片代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08