Django提供了一个高级联合供稿生成框架,可以轻松创建RSS和Atom供稿。 RSS和Atom都是基于XML的格式,可以用来自动更新网站内容的提要。 在这里阅读更多关于RSS的信息,并在这里获取有关Atom的信息。
要创建任何联合供稿,您只需编写一个简短的Python类。 您可以根据需要创建尽可能多的Feed。 Django还附带了一个较低级别的Feed生成API。 如果您想要在Web上下文之外生成订阅源,或者使用其他某种更低级的方式生成订阅源,请使用此选项。
高级框架
概观
高级Feed生成框架由Feed类提供。 要创建一个feed,请写一个Feed类并在URLconf中指向它的一个实例。
Feed类
Feed类是一个表示联合供稿的Python类。 馈送可以是简单的(例如,网站新闻馈送或显示博客的最新条目的基本馈送)或更复杂(例如,显示特定类别中的所有博客条目的馈送,其中类别是可变的)。 Feed类的子类django.contrib.syndication.views.Feed。 他们可以生活在你的代码库的任何地方。 Feed类的实例是可以在你的URLconf中使用的视图。
一个简单的例子
这个简单的例子来自一个假设的警察新闻网站,描述了最新的五个新闻项目的饲料:
from django.contrib.syndication.views import Feed
from django.core.urlresolvers import reverse
from policebeat.models import NewsItem
class LatestEntriesFeed(Feed):
title = "Police beat site news"
link = "/sitenews/"
description = "Updates on changes and additions to police beat central."
def items(self):
return NewsItem.objects.order_by('-pub_date')[:5]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.description
# item_link is only needed if NewsItem has no get_absolute_url method.
def item_link(self, item):
return reverse('news-item', args=[item.pk])
要将URL连接到此Feed,请将Feed对象的实例放入URLconf中。 例如:
from django.conf.urls import url
from myproject.feeds import LatestEntriesFeed
urlpatterns = [
# ...
url(r'^latest/feed/$', LatestEntriesFeed()),
# ...
]
注意:
- Feed类的子类django.contrib.syndication.views.Feed。
- 标题,链接和描述分别对应于标准RSS <title>,<link>和<description>元素。
- items()简单地说就是一个方法,它返回应该作为<item>元素包含在Feed中的对象列表。 尽管此示例使用Django的对象关系映射返回NewsItem对象,但不必返回模型实例。 尽管您可以通过使用Django模型免费获得一些功能,但items()可以返回您想要的任何类型的对象。
- 如果您要创建Atom feed而不是RSS feed,请设置字幕属性而不是描述属性。 例如,请参阅本章后面的发布Atom和RSS源。
有一件事是要做的。 在RSS feed中,每个<item>都有一个<title>,<link>和<description>。 我们需要告诉框架将哪些数据放入这些元素。
对于<title>和<description>的内容,Django会尝试在Feed类中调用方法item_title()和item_description()。 它们传递一个参数,item,它是对象本身。 这些是可选的; 默认情况下,对象的Unicode代表用于两者。
如果您想为标题或描述进行特殊格式化,可以使用Django模板。 它们的路径可以通过Feed类中的title_template和description_template属性来指定。 为每个项目呈现模板并传递两个模板上下文变量:
- {{obj}} - 当前对象(您在item()中返回的任何对象之一)。
- {{site}} - 代表当前网站的Django网站对象。 这对{{site.domain}}或{{site.name}}很有用。
请参阅下面使用说明模板的“复杂示例”。
如果您需要提供比前面提到的两个变量更多的信息,还可以将附加信息传递给标题和描述模板。 您可以在Feed子类中提供get_context_data方法的实现。 例如:
from mysite.models import Article
from django.contrib.syndication.views import Feed
class ArticlesFeed(Feed):
title = "My articles"
description_template = "feeds/articles.html"
def items(self):
return Article.objects.order_by('-pub_date')[:5]
def get_context_data(self, **kwargs):
context = super(ArticlesFeed, self).get_context_data(**kwargs)
context['foo'] = 'bar'
return context
在模版中
Something about {{ foo }}: {{ obj.description }}
这个方法将被item()返回的列表中的每个项目调用一次,其中包含以下关键字参数:
-
item:当前item。 出于向后兼容性的原因,此上下文变量的名称是{{obj}}。
-
obj:get_object()返回的对象。 默认情况下,这不会暴露给模板以避免与{{obj}}混淆(参见上文),但是您可以在实现get_context_data()时使用它。
-
site:如上所述的当前网站。
-
request:当前请求。
get_context_data()的行为模仿通用视图的行为 - 您应该调用super()从父类中检索上下文数据,添加数据并返回修改过的字典。
要指定<link>的内容,您有两个选项。 对于items()中的每个item,Django首先尝试调用Feed类中的item_link()方法。 以类似于标题和说明的方式,它传递了一个参数 - item。 如果该方法不存在,Django会尝试对该对象执行get_absolute_url()方法。
get_absolute_url()和item_link()都应该以正常的Python字符串的形式返回item的URL。 与get_absolute_url()一样,item_link()的结果将直接包含在URL中,因此您需要负责在方法本身内进行所有必要的URL引用和转换为ASCII。
一个复杂的例子
该框架还通过参数支持更复杂的提要。 例如,一个网站可以提供针对城市中每个警察的近期犯罪的RSS源。 为每个警察创建一个单独的饲料班是愚蠢的; 这会违反DRY原则并将数据耦合到编程逻辑。
相反,联合框架允许您访问从您的URLconf传递的参数,以便提要可以根据Feed的URL中的信息输出项目。 警察击败饲料可以通过这样的URL访问:
- /beats/613/rss/ – 返回最近feed613条犯罪记录.
- /beats/1424/rss/ – 返回最近feed1424条犯罪记录.
这些可以与URLconf行匹配,例如:
url(r'^beats/(?P[0-9]+)/rss/$', BeatFeed()),
与视图一样,URL中的参数与请求对象一起被传递给get_object()方法。 以下是这些特定于节拍的提要的代码:
from django.contrib.syndication.views import FeedDoesNotExist
from django.shortcuts import get_object_or_404
class BeatFeed(Feed):
description_template = 'feeds/beat_description.html'
def get_object(self, request, beat_id):
return get_object_or_404(Beat, pk=beat_id)
def title(self, obj):
return "Police beat central: Crimes for beat %s" % obj.beat
def link(self, obj):
return obj.get_absolute_url()
def description(self, obj):
return "Crimes recently reported in police beat %s" % obj.beat
def items(self, obj):
return Crime.objects.filter(beat=obj).order_by('-crime_date')[:30]
为了生成feed的<title>,<link>和<description>,Django使用title(),link()和description()方法。
在前面的例子中,它们是简单的字符串类属性,但这个例子说明它们可以是字符串或方法。 对于标题,链接和描述中的每一个,Django都遵循以下算法:
- 首先,它尝试调用一个方法,传递obj参数,其中obj是get_object()返回的对象。
- 否则,它会尝试调用一个没有参数的方法。
- 如果没有,它使用class属性。
还要注意,items()也遵循相同的算法 - 首先,它会尝试item(obj),然后item(),然后最后一个item类属性(应该是一个列表)。 我们正在使用项目描述的模板。 它可以非常简单:
{{ obj.description }}
但是,您可以根据需要自由添加格式。 下面的ExampleFeed类提供了有关Feed类的方法和属性的完整文档。
指定Feed的类型
默认情况下,此框架中生成的供稿使用RSS 2.0。 要改变这一点,请向Feed类添加feed_type属性,如下所示:
from django.utils.feedgenerator import Atom1Feed
class MyFeed(Feed):
feed_type = Atom1Feed
请注意,您将feed_type设置为类对象,而不是实例。 目前可用的Feed类型是:
- django.utils.feedgenerator.Rss201rev2Feed (RSS 2.01. Default.)
- django.utils.feedgenerator.RssUserland091Feed (RSS 0.91.)
- django.utils.feedgenerator.Atom1Feed (Atom 1.0.)
外壳
要指定附件(如用于创建Podcast Feed的附件),请使用item_enclosure_url,item_enclosure_length和item_enclosure_mime_type挂钩。有关使用示例,请参阅下面的ExampleFeed类。
语言
由联合框架创建的源自动包含适当的<language>标记(RSS 2.0)或xml:lang属性(Atom)。这直接来自您的LANGUAGE_CODE设置。
网址
链接方法/属性可以返回绝对路径(例如/ blog /)或具有完全限定的域和协议的URL(例如http://www.example.com/blog/)。如果链接不返回域,联合框架将根据您的SITE_ID设置插入当前站点的域。 Atom提要需要<link rel =“self”>来定义提要的当前位置。联合框架根据SITE_ID设置自动填充当前网站的域。
串联发布Atom和RSS源
一些开发人员喜欢提供他们的提要的Atom和RSS版本。使用Django很容易:只需创建Feed类的子类并将feed_type设置为不同的东西即可。然后更新你的URLconf以添加额外的版本。这里有一个完整的例子:
from django.contrib.syndication.views import Feed
from policebeat.models import NewsItem
from django.utils.feedgenerator import Atom1Feed
class RssSiteNewsFeed(Feed):
title = "Police beat site news"
link = "/sitenews/"
description = "Updates on changes and additions to police beat central."
def items(self):
return NewsItem.objects.order_by('-pub_date')[:5]
class AtomSiteNewsFeed(RssSiteNewsFeed):
feed_type = Atom1Feed
subtitle = RssSiteNewsFeed.description
在此示例中,RSS提要使用描述,而Atom提要使用子标题。 这是因为Atom Feed不提供Feed级别的描述,但它们确实提供了子标题。 如果您在Feed类中提供了说明,则Django不会自动将其添加到子标题元素中,因为子标题和说明不一定是相同的东西。 相反,你应该定义一个子标题属性。
在上面的例子中,我们只需将Atom feeds字幕设置为RSS订阅源描述,因为它已经很短了。 和随附的URLconf:
from django.conf.urls import url
from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed
urlpatterns = [
# ...
url(r'^sitenews/rss/$', RssSiteNewsFeed()),
url(r'^sitenews/atom/$', AtomSiteNewsFeed()),
# ...
]
有关说明Feed类的所有可能属性和方法的示例,请参阅供稿类参考。
低级框架
在幕后,高层次的RSS框架使用较低层框架来生成提要的XML。 该框架位于单个模块中:django / utils / feedgenerator.py。 您可以自行使用此框架,以生成较低级别的Feed。 您还可以创建自定义Feed生成器子类以用于feed_type Feed选项。
SyndicationFeed类
feedgenerator模块包含一个基类:
- django.utils.feedgenerator.SyndicationFeed
和几个子类:
- django.utils.feedgenerator.RssUserland091Feed
- django.utils.feedgenerator.Rss201rev2Feed
- django.utils.feedgenerator.Atom1Feed
这三个类中的每一个都知道如何将某种类型的feed呈现为XML。 他们共享这个界面:
SyndicationFeed.init()
使用适用于整个Feed的元数据字典初始化Feed。 所需的关键字参数是:
- title
- link
- description
还有其他一些可选的关键字:
- language
- author_email
- author_name
- author_link
- subtitle
- categories
- feed_url
- feed_copyright
- feed_guid
- ttl
您传递给init的任何额外关键字参数都将存储在self.feed中,以用于定制Feed生成器。 所有参数都应该是Unicode对象,但类别除外,它们应该是Unicode对象的序列。
SyndicationFeed.add_item()
使用给定参数向Feed添加item。
所需的关键字参数是:
- title
- link
- description
可选的关键字参数是:
-
author_email
-
author_name
-
author_link
-
pubdate
-
comments
-
unique_id
-
enclosure
-
categories
-
item_copyright
-
ttl
-
updateddate
额外的关键字参数将被存储为自定义feed生成器。 所有的参数,如果给出,应该是Unicode对象,除了:
- pubdate应该是一个Python日期时间对象。
- updateddate应该是一个Python日期时间对象。
- 外壳应该是django.utils.feedgenerator.Enclosure的一个实例。
- 类别应该是一系列的Unicode对象。
SyndicationFeed.write()
将给定编码中的馈送输出到outfile,这是一个类似文件的对象。
SyndicationFeed.writeString()
以给定编码中的字符串形式返回提要。 例如,要创建一个Atom 1.0提要并将其打印到标准输出:
>>> from django.utils import feedgenerator
>>> from datetime import datetime
>>> f = feedgenerator.Atom1Feed(
... title="My Weblog",
... link="http://www.example.com/",
... description="In which I write about what I ate today.",
... language="en",
... author_name="Myself",
... feed_url="http://example.com/atom.xml")
>>> f.add_item(title="Hot dog today",
... link="http://www.example.com/entries/1/",
... pubdate=datetime.now(),
... description="<p>Today I had a Vienna Beef hot dog. It was pink, plump and per\
fect.</p>")
>>> print(f.writeString('UTF-8'))
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
...
</feed>
自定义Feed生成器
如果您需要制作自定义Feed格式,那么您有几个选项。如果Feed格式是完全自定义的,那么您需要继承SyndicationFeed并完全替换write()和writeString()方法。但是,如果Feed格式是RSS或Atom的副产品(即GeoRSS,Apple的iTunes播客格式等),则您有更好的选择。
这些类型的提要通常会为底层格式添加额外的元素和/或属性,并且SyndicationFeed会调用一组方法来获取这些额外的属性。因此,您可以继承相应的Feed生成器类(Atom1Feed或Rss201rev2Feed)并扩展这些回调。他们是:
SyndicationFeed.root_attributes(self,)
返回要添加到根提要素(提要/通道)的属性字典。
SyndicationFeed.add_root_elements(self,handler)
回调在根Feed元素(feed / channel)中添加元素。处理程序是Python内置SAX库的XMLGenerator;您将调用其中的方法来添加到正在处理的XML文档中。
SyndicationFeed.item_attributes(self,item)
返回要添加到每个项目(item / entry)元素的属性字典。参数item是传递给SyndicationFeed.add_item()的所有数据的字典。
SyndicationFeed.add_item_elements(self,handler,item)
回调添加元素到每个项目(item / entry)元素。处理程序和项目如上所述。
如果您重写了这些方法中的任何一个,请确保调用超类方法,因为它们为每种提要格式添加了必需的元素。
例如,您可能会开始实施iTunes RSS Feed生成器,如下所示:
class iTunesFeed(Rss201rev2Feed):
def root_attributes(self):
attrs = super(iTunesFeed, self).root_attributes()
attrs['xmlns:itunes'] =
'http://www.itunes.com/dtds/podcast-1.0.dtd'
return attrs
def add_root_elements(self, handler):
super(iTunesFeed, self).add_root_elements(handler)
handler.addQuickElement('itunes:explicit', 'clean')
很明显,要完成一个完整的自定义feed类还有很多工作要做,但上面的例子应该说明基本思想。
网友评论