summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorUnai Zalakain <unai@gisa-elkartea.org>2015-08-21 11:50:43 +0200
committerTim Graham <timograham@gmail.com>2015-09-18 18:31:58 -0400
commitaac2a2d2ae2486342058db0c72ed7ba2c7c8eb1e (patch)
tree9d36cf0b889eceb832aee1ffbeea0a826a557b22 /django
parent71ebcb85b931f43865df5b322b2cf06d3da23f69 (diff)
Fixed #13110 -- Added support for multiple enclosures in Atom feeds.
The ``item_enclosures`` hook returns a list of ``Enclosure`` objects which is then used by the feed builder. If the feed is a RSS feed, an exception is raised as RSS feeds don't allow multiple enclosures per feed item. The ``item_enclosures`` hook defaults to an empty list or, if the ``item_enclosure_url`` hook is defined, to a list with a single ``Enclosure`` built from the ``item_enclosure_url``, ``item_enclosure_length``, and ``item_enclosure_mime_type`` hooks.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/syndication/views.py22
-rw-r--r--django/utils/feedgenerator.py52
2 files changed, 50 insertions, 24 deletions
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index 7bcc951611..2e5e5f3ef9 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -64,6 +64,17 @@ class Feed(object):
'item_link() method in your Feed class.' % item.__class__.__name__
)
+ def item_enclosures(self, item):
+ enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
+ if enc_url:
+ enc = feedgenerator.Enclosure(
+ url=smart_text(enc_url),
+ length=smart_text(self.__get_dynamic_attr('item_enclosure_length', item)),
+ mime_type=smart_text(self.__get_dynamic_attr('item_enclosure_mime_type', item)),
+ )
+ return [enc]
+ return []
+
def __get_dynamic_attr(self, attname, obj, default=None):
try:
attr = getattr(self, attname)
@@ -171,14 +182,7 @@ class Feed(object):
self.__get_dynamic_attr('item_link', item),
request.is_secure(),
)
- enc = None
- enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
- if enc_url:
- enc = feedgenerator.Enclosure(
- url=smart_text(enc_url),
- length=smart_text(self.__get_dynamic_attr('item_enclosure_length', item)),
- mime_type=smart_text(self.__get_dynamic_attr('item_enclosure_mime_type', item))
- )
+ enclosures = self.__get_dynamic_attr('item_enclosures', item)
author_name = self.__get_dynamic_attr('item_author_name', item)
if author_name is not None:
author_email = self.__get_dynamic_attr('item_author_email', item)
@@ -203,7 +207,7 @@ class Feed(object):
unique_id=self.__get_dynamic_attr('item_guid', item, link),
unique_id_is_permalink=self.__get_dynamic_attr(
'item_guid_is_permalink', item),
- enclosure=enc,
+ enclosures=enclosures,
pubdate=pubdate,
updateddate=updateddate,
author_name=author_name,
diff --git a/django/utils/feedgenerator.py b/django/utils/feedgenerator.py
index 9b1421160b..c67fedb277 100644
--- a/django/utils/feedgenerator.py
+++ b/django/utils/feedgenerator.py
@@ -118,11 +118,13 @@ class SyndicationFeed(object):
def add_item(self, title, link, description, author_email=None,
author_name=None, author_link=None, pubdate=None, comments=None,
unique_id=None, unique_id_is_permalink=None, enclosure=None,
- categories=(), item_copyright=None, ttl=None, updateddate=None, **kwargs):
+ categories=(), item_copyright=None, ttl=None, updateddate=None,
+ enclosures=None, **kwargs):
"""
Adds an item to the feed. All args are expected to be Python Unicode
objects except pubdate and updateddate, which are datetime.datetime
- objects, and enclosure, which is an instance of the Enclosure class.
+ objects, and enclosures, which is an iterable of instances of the
+ Enclosure class.
"""
to_unicode = lambda s: force_text(s, strings_only=True)
if categories:
@@ -130,6 +132,16 @@ class SyndicationFeed(object):
if ttl is not None:
# Force ints to unicode
ttl = force_text(ttl)
+ if enclosure is None:
+ enclosures = [] if enclosures is None else enclosures
+ else:
+ warnings.warn(
+ "The enclosure keyword argument is deprecated, "
+ "use enclosures instead.",
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
+ enclosures = [enclosure]
item = {
'title': to_unicode(title),
'link': iri_to_uri(link),
@@ -142,7 +154,7 @@ class SyndicationFeed(object):
'comments': to_unicode(comments),
'unique_id': to_unicode(unique_id),
'unique_id_is_permalink': unique_id_is_permalink,
- 'enclosure': enclosure,
+ 'enclosures': enclosures,
'categories': categories or (),
'item_copyright': to_unicode(item_copyright),
'ttl': ttl,
@@ -317,10 +329,19 @@ class Rss201rev2Feed(RssFeed):
handler.addQuickElement("ttl", item['ttl'])
# Enclosure.
- if item['enclosure'] is not None:
- handler.addQuickElement("enclosure", '',
- {"url": item['enclosure'].url, "length": item['enclosure'].length,
- "type": item['enclosure'].mime_type})
+ if item['enclosures']:
+ enclosures = list(item['enclosures'])
+ if len(enclosures) > 1:
+ raise ValueError(
+ "RSS feed items may only have one enclosure, see "
+ "http://www.rssboard.org/rss-profile#element-channel-item-enclosure"
+ )
+ enclosure = enclosures[0]
+ handler.addQuickElement('enclosure', '', {
+ 'url': enclosure.url,
+ 'length': enclosure.length,
+ 'type': enclosure.mime_type,
+ })
# Categories.
for cat in item['categories']:
@@ -328,7 +349,7 @@ class Rss201rev2Feed(RssFeed):
class Atom1Feed(SyndicationFeed):
- # Spec: http://atompub.org/2005/07/11/draft-ietf-atompub-format-10.html
+ # Spec: https://tools.ietf.org/html/rfc4287
content_type = 'application/atom+xml; charset=utf-8'
ns = "http://www.w3.org/2005/Atom"
@@ -405,13 +426,14 @@ class Atom1Feed(SyndicationFeed):
if item['description'] is not None:
handler.addQuickElement("summary", item['description'], {"type": "html"})
- # Enclosure.
- if item['enclosure'] is not None:
- handler.addQuickElement("link", '',
- {"rel": "enclosure",
- "href": item['enclosure'].url,
- "length": item['enclosure'].length,
- "type": item['enclosure'].mime_type})
+ # Enclosures.
+ for enclosure in item.get('enclosures') or []:
+ handler.addQuickElement('link', '', {
+ 'rel': 'enclosure',
+ 'href': enclosure.url,
+ 'length': enclosure.length,
+ 'type': enclosure.mime_type,
+ })
# Categories.
for cat in item['categories']: