Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixed #14656 -- Atom1Feed should write atom:published element #1366

Closed
wants to merge 2 commits into from

2 participants

@Matt-Deacalion

https://code.djangoproject.com/ticket/14656

The first commit – e51e589 was some housekeeping because I was in the neighbourhood… if it's cluttering the history I'll remove it. Cheers. :monkey_face:

django/utils/feedgenerator.py
((8 lines not shown))
"""
- updates = [i['pubdate'] for i in self.items if i['pubdate'] is not None]
- if len(updates) > 0:
- updates.sort()
- return updates[-1]
+ updated = [i['updateddate'] for i in self.items
@timgraham Owner

should this consider both updateteddate and pubdate together? i.e. right now if entry A has updatedated date yesterday and entry B has pubdate today, it looks like entry A will be considered the latest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
django/utils/feedgenerator.py
@@ -112,13 +112,14 @@ def __init__(self, title, link, description, language=None, author_email=None,
self.items = []
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, **kwargs):
+ author_name=None, author_link=None, pubdate=None,
+ updateddate=None, comments=None, unique_id=None,
@timgraham Owner

not listing updateddate as the last kwarg is technically backwards incompatible if someone is calling this item using args instead of kwargs but it seems unlikely to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
docs/ref/contrib/syndication.txt
@@ -922,6 +940,7 @@ They share this interface:
* ``author_name``
* ``author_link``
* ``pubdate``
+ * ``updateddate``
@timgraham Owner

there should be a .. versionadded:: 1.7 somewhere here that notes when updateddate was added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
docs/ref/utils.txt
@@ -342,11 +342,11 @@ SyndicationFeed
All parameters should be Unicode objects, except ``categories``, which
should be a sequence of Unicode objects.
- .. method:: add_item(title, link, description, [author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, **kwargs])
+ .. method:: add_item(title, link, description, [author_email=None, author_name=None, author_link=None, pubdate=None, updateddate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, **kwargs])
@timgraham Owner

same as above, needs a versionadded

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/syndication/tests.py
@@ -257,12 +356,14 @@ def test_aware_datetime_conversion(self):
"""
response = self.client.get('/syndication/aware-dates/')
doc = minidom.parseString(response.content)
- updated = doc.getElementsByTagName('updated')[0].firstChild.wholeText
- self.assertEqual(updated[-6:], '+00:42')
+ published = doc.getElementsByTagName('published')[0].\
@timgraham Owner

I think I'd prefer not to make the PEP8 changes, the existing style seems fine to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Matt-Deacalion

Thanks for the feedback Tim, I've made the changes you suggested.

@Matt-Deacalion Matt-Deacalion Fixed #14656 -- Atom1Feed `published` element
Some feed aggregators make use of the `published` element as well as
the `updated` element (within the Atom standard -- http://bit.ly/2YySb).

The standard allows for these two elements to be present in the same
entry. `Atom1Feed` had implemented the `updated` element which was
incorrectly taking the date from `pubdate`.
fed4059
django/utils/feedgenerator.py
((8 lines not shown))
"""
- updates = [i['pubdate'] for i in self.items if i['pubdate'] is not None]
- if len(updates) > 0:
- updates.sort()
- return updates[-1]
+ dates = []
+
+ for item in self.items:
+ for k, v in item.iteritems():
@timgraham Owner

I don't think there's a need to iterate through all the items values. Just check if the two we're interested in exist?

Also, could you add a test for the issue I pointed out that's been fixed here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Matt-Deacalion

I've updated the latest_post_date method, it doesn't iterate through all the values now. I've also added a test for this method. Thanks for the code review. :-)

@timgraham
Owner

made some final tweaks and merged in a269ea4 - thanks Matt!

@timgraham timgraham closed this
@Matt-Deacalion

Great, nice changes in latest_post_date!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 17, 2013
  1. @Matt-Deacalion
Commits on Jul 19, 2013
  1. @Matt-Deacalion

    Fixed #14656 -- Atom1Feed `published` element

    Matt-Deacalion authored
    Some feed aggregators make use of the `published` element as well as
    the `updated` element (within the Atom standard -- http://bit.ly/2YySb).
    
    The standard allows for these two elements to be present in the same
    entry. `Atom1Feed` had implemented the `updated` element which was
    incorrectly taking the date from `pubdate`.
This page is out of date. Refresh to see the latest.
View
1  AUTHORS
@@ -204,6 +204,7 @@ answer newbie questions, and generally made Django that much better:
Clint Ecker
Nick Efford <nick@efford.org>
Marc Egli <frog32@me.com>
+ Matt Deacalion Stevens <matt@dirtymonkey.co.uk>
eibaan@gmail.com
David Eklund
Julia Elman
View
12 django/contrib/syndication/views.py
@@ -43,9 +43,9 @@ def __call__(self, request, *args, **kwargs):
raise Http404('Feed object does not exist.')
feedgen = self.get_feed(obj, request)
response = HttpResponse(content_type=feedgen.mime_type)
- if hasattr(self, 'item_pubdate'):
- # if item_pubdate is defined for the feed, set header so as
- # ConditionalGetMiddleware is able to send 304 NOT MODIFIED
+ if hasattr(self, 'item_pubdate') or hasattr(self, 'item_updateddate'):
+ # if item_pubdate or item_updateddate is defined for the feed, set
+ # header so as ConditionalGetMiddleware is able to send 304 NOT MODIFIED
response['Last-Modified'] = http_date(
timegm(feedgen.latest_post_date().utctimetuple()))
feedgen.write(response, 'utf-8')
@@ -191,6 +191,11 @@ def get_feed(self, obj, request):
ltz = tzinfo.LocalTimezone(pubdate)
pubdate = pubdate.replace(tzinfo=ltz)
+ updateddate = self.__get_dynamic_attr('item_updateddate', item)
+ if updateddate and is_naive(updateddate):
+ ltz = tzinfo.LocalTimezone(updateddate)
+ updateddate = updateddate.replace(tzinfo=ltz)
+
feed.add_item(
title = title,
link = link,
@@ -200,6 +205,7 @@ def get_feed(self, obj, request):
'item_guid_is_permalink', item),
enclosure = enc,
pubdate = pubdate,
+ updateddate = updateddate,
author_name = author_name,
author_email = author_email,
author_link = author_link,
View
38 django/utils/feedgenerator.py
@@ -112,13 +112,14 @@ def __init__(self, title, link, description, language=None, author_email=None,
self.items = []
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, **kwargs):
+ 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):
"""
Adds an item to the feed. All args are expected to be Python Unicode
- objects except pubdate, which is a datetime.datetime object, and
- enclosure, which is an instance of the Enclosure class.
+ objects except pubdate and updateddate, which are datetime.datetime
+ objects, and enclosure, which is an instance of the Enclosure class.
"""
to_unicode = lambda s: force_text(s, strings_only=True)
if categories:
@@ -134,6 +135,7 @@ def add_item(self, title, link, description, author_email=None,
'author_name': to_unicode(author_name),
'author_link': iri_to_uri(author_link),
'pubdate': pubdate,
+ 'updateddate': updateddate,
'comments': to_unicode(comments),
'unique_id': to_unicode(unique_id),
'unique_id_is_permalink': unique_id_is_permalink,
@@ -191,13 +193,21 @@ def writeString(self, encoding):
def latest_post_date(self):
"""
- Returns the latest item's pubdate. If none of them have a pubdate,
- this returns the current date/time.
+ Returns the latest item's pubdate or updateddate. If no items
+ have either of these attributes this returns the current date/time.
"""
- updates = [i['pubdate'] for i in self.items if i['pubdate'] is not None]
- if len(updates) > 0:
- updates.sort()
- return updates[-1]
+ dates = []
+
+ for item in self.items:
+ if item.get('updateddate', False):
+ dates.append(item['updateddate'])
+
+ if item.get('pubdate', False):
+ dates.append(item['pubdate'])
+
+ if len(dates) > 0:
+ dates.sort()
+ return dates[-1]
else:
return datetime.datetime.now()
@@ -349,8 +359,12 @@ def write_items(self, handler):
def add_item_elements(self, handler, item):
handler.addQuickElement("title", item['title'])
handler.addQuickElement("link", "", {"href": item['link'], "rel": "alternate"})
+
if item['pubdate'] is not None:
- handler.addQuickElement("updated", rfc3339_date(item['pubdate']))
+ handler.addQuickElement('published', rfc3339_date(item['pubdate']))
+
+ if item['updateddate'] is not None:
+ handler.addQuickElement('updated', rfc3339_date(item['updateddate']))
# Author information.
if item['author_name'] is not None:
View
24 docs/ref/contrib/syndication.txt
@@ -815,6 +815,24 @@ This example illustrates all possible attributes and methods for a
item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate.
+ # ITEM UPDATED -- It's optional to use one of these three. This is a
+ # hook that specifies how to get the updateddate for a given item.
+ # In each case, the method/attribute should return a Python
+ # datetime.datetime object.
+
+ def item_updateddate(self, item):
+ """
+ Takes an item, as returned by items(), and returns the item's
+ updateddate.
+ """
+
+ def item_updateddate(self):
+ """
+ Returns the updateddated for every item in the feed.
+ """
+
+ item_updateddate = datetime.datetime(2005, 5, 3) # Hard-coded updateddate.
+
# ITEM CATEGORIES -- It's optional to use one of these three. This is
# a hook that specifies how to get the list of categories for a given
# item. In each case, the method/attribute should return an iterable
@@ -928,16 +946,22 @@ They share this interface:
* ``categories``
* ``item_copyright``
* ``ttl``
+ * ``updateddate``
Extra keyword arguments will be stored for `custom feed generators`_.
All parameters, if given, should be Unicode objects, except:
* ``pubdate`` should be a Python :class:`~datetime.datetime` object.
+ * ``updateddate`` should be a Python :class:`~datetime.datetime` object.
* ``enclosure`` should be an instance of
:class:`django.utils.feedgenerator.Enclosure`.
* ``categories`` should be a sequence of Unicode objects.
+ .. versionadded:: 1.7
+
+ The optional ``updateddate`` argument was added.
+
:meth:`.SyndicationFeed.write`
Outputs the feed in the given encoding to outfile, which is a file-like object.
View
14 docs/ref/utils.txt
@@ -342,11 +342,15 @@ SyndicationFeed
All parameters should be Unicode objects, except ``categories``, which
should be a sequence of Unicode objects.
- .. method:: add_item(title, link, description, [author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, **kwargs])
+ .. method:: add_item(title, link, description, [author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, enclosure=None, categories=(), item_copyright=None, ttl=None, updateddate=None, **kwargs])
Adds an item to the feed. All args are expected to be Python ``unicode``
- objects except ``pubdate``, which is a ``datetime.datetime`` object, and
- ``enclosure``, which is an instance of the ``Enclosure`` class.
+ objects except ``pubdate`` and ``updateddate``, which are ``datetime.datetime``
+ objects, and ``enclosure``, which is an instance of the ``Enclosure`` class.
+
+ .. versionadded:: 1.7
+
+ The optional ``updateddate`` argument was added.
.. method:: num_items()
@@ -380,8 +384,8 @@ SyndicationFeed
.. method:: latest_post_date()
- Returns the latest item's ``pubdate``. If none of them have a
- ``pubdate``, this returns the current date/time.
+ Returns the latest item's ``pubdate`` or ``updateddate`` date. If no items
+ have either of these attributes this returns the current date/time.
Enclosure
---------
View
5 docs/releases/1.7.txt
@@ -67,6 +67,11 @@ Minor features
parameters that are passed to the ``dict`` constructor used to build the new
context level.
+* The :class:`~django.utils.feedgenerator.Atom1Feed` syndication feed's
+ ``updated`` element now utilizes `updateddate` instead of ``pubdate``,
+ allowing the ``published`` element to be included in the feed (which
+ relies on ``pubdate``).
+
Backwards incompatible changes in 1.7
=====================================
View
20 tests/syndication/feeds.py
@@ -33,7 +33,10 @@ def item_description(self, item):
return "Overridden description: %s" % item
def item_pubdate(self, item):
- return item.date
+ return item.published
+
+ def item_updateddate(self, item):
+ return item.updated
item_author_name = 'Sally Smith'
item_author_email = 'test@example.com'
@@ -72,6 +75,17 @@ class TestAtomFeed(TestRss2Feed):
subtitle = TestRss2Feed.description
+class TestLatestFeed(TestRss2Feed):
+ """
+ A feed where the latest entry date is an `updated` element.
+ """
+ feed_type = feedgenerator.Atom1Feed
+ subtitle = TestRss2Feed.description
+
+ def items(self):
+ return Entry.objects.exclude(pk=5)
+
+
class ArticlesFeed(TestRss2Feed):
"""
A feed to test no link being defined. Articles have no get_absolute_url()
@@ -115,7 +129,7 @@ class NaiveDatesFeed(TestAtomFeed):
A feed with naive (non-timezone-aware) dates.
"""
def item_pubdate(self, item):
- return item.date
+ return item.published
class TZAwareDatesFeed(TestAtomFeed):
@@ -126,7 +140,7 @@ def item_pubdate(self, item):
# Provide a weird offset so that the test can know it's getting this
# specific offset and not accidentally getting on from
# settings.TIME_ZONE.
- return item.date.replace(tzinfo=tzinfo.FixedOffset(42))
+ return item.published.replace(tzinfo=tzinfo.FixedOffset(42))
class TestFeedUrlFeed(TestAtomFeed):
View
21 tests/syndication/fixtures/feeddata.json
@@ -4,7 +4,8 @@
"pk": 1,
"fields": {
"title": "My first entry",
- "date": "1850-01-01 12:30:00"
+ "updated": "1850-01-01 12:30:00",
+ "published": "1066-09-25 20:15:00"
}
},
{
@@ -12,7 +13,8 @@
"pk": 2,
"fields": {
"title": "My second entry",
- "date": "2008-01-02 12:30:00"
+ "updated": "2008-01-02 12:30:00",
+ "published": "2006-03-17 18:00:00"
}
},
{
@@ -20,7 +22,8 @@
"pk": 3,
"fields": {
"title": "My third entry",
- "date": "2008-01-02 13:30:00"
+ "updated": "2008-01-02 13:30:00",
+ "published": "2005-06-14 10:45:00"
}
},
{
@@ -28,7 +31,17 @@
"pk": 4,
"fields": {
"title": "A & B < C > D",
- "date": "2008-01-03 13:30:00"
+ "updated": "2008-01-03 13:30:00",
+ "published": "2005-11-25 12:11:23"
+ }
+ },
+ {
+ "model": "syndication.entry",
+ "pk": 5,
+ "fields": {
+ "title": "My last entry",
+ "updated": "2013-01-20 00:00:00",
+ "published": "2013-03-25 20:00:00"
}
},
{
View
6 tests/syndication/models.py
@@ -5,10 +5,11 @@
@python_2_unicode_compatible
class Entry(models.Model):
title = models.CharField(max_length=200)
- date = models.DateTimeField()
+ updated = models.DateTimeField()
+ published = models.DateTimeField()
class Meta:
- ordering = ('date',)
+ ordering = ('updated',)
def __str__(self):
return self.title
@@ -24,4 +25,3 @@ class Article(models.Model):
def __str__(self):
return self.title
-
View
164 tests/syndication/tests.py
@@ -25,12 +25,17 @@ def assertChildNodeContent(self, elem, expected):
elem.getElementsByTagName(k)[0].firstChild.wholeText, v)
def assertCategories(self, elem, expected):
- self.assertEqual(set(i.firstChild.wholeText for i in elem.childNodes if i.nodeName == 'category'), set(expected))
+ self.assertEqual(
+ set(i.firstChild.wholeText
+ for i in elem.childNodes
+ if i.nodeName == 'category'),
+ set(expected))
######################################
# Feed view
######################################
+
class SyndicationFeedTest(FeedTestCase):
"""
Tests for the high-level syndication feed framework.
@@ -58,11 +63,22 @@ def test_rss2_feed(self):
chan = chan_elem[0]
# Find the last build date
- d = Entry.objects.latest('date').date
+ d = Entry.objects.latest('published').published
ltz = tzinfo.LocalTimezone(d)
last_build_date = rfc2822_date(d.replace(tzinfo=ltz))
- self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category'])
+ self.assertChildNodes(chan, [
+ 'title',
+ 'link',
+ 'description',
+ 'language',
+ 'lastBuildDate',
+ 'item',
+ 'atom:link',
+ 'ttl',
+ 'copyright',
+ 'category',
+ ])
self.assertChildNodeContent(chan, {
'title': 'My blog',
'description': 'A more thorough description of my blog.',
@@ -88,7 +104,7 @@ def test_rss2_feed(self):
)
# Find the pubdate of the first feed item
- d = Entry.objects.get(pk=1).date
+ d = Entry.objects.get(pk=1).published
ltz = tzinfo.LocalTimezone(d)
pub_date = rfc2822_date(d.replace(tzinfo=ltz))
@@ -104,7 +120,15 @@ def test_rss2_feed(self):
})
self.assertCategories(items[0], ['python', 'testing'])
for item in items:
- self.assertChildNodes(item, ['title', 'link', 'description', 'guid', 'category', 'pubDate', 'author'])
+ self.assertChildNodes(item, [
+ 'title',
+ 'link',
+ 'description',
+ 'guid',
+ 'category',
+ 'pubDate',
+ 'author',
+ ])
# Assert that <guid> does not have any 'isPermaLink' attribute
self.assertIsNone(item.getElementsByTagName(
'guid')[0].attributes.get('isPermaLink'))
@@ -143,7 +167,8 @@ def test_rss2_feed_guid_permalink_true(self):
def test_rss091_feed(self):
"""
- Test the structure and content of feeds generated by RssUserland091Feed.
+ Test the structure and content of feeds
+ generated by RssUserland091Feed.
"""
response = self.client.get('/syndication/rss091/')
doc = minidom.parseString(response.content)
@@ -160,7 +185,18 @@ def test_rss091_feed(self):
chan_elem = feed.getElementsByTagName('channel')
self.assertEqual(len(chan_elem), 1)
chan = chan_elem[0]
- self.assertChildNodes(chan, ['title', 'link', 'description', 'language', 'lastBuildDate', 'item', 'atom:link', 'ttl', 'copyright', 'category'])
+ self.assertChildNodes(chan, [
+ 'title',
+ 'link',
+ 'description',
+ 'language',
+ 'lastBuildDate',
+ 'item',
+ 'atom:link',
+ 'ttl',
+ 'copyright',
+ 'category',
+ ])
# Ensure the content of the channel is correct
self.assertChildNodeContent(chan, {
@@ -194,32 +230,119 @@ def test_atom_feed(self):
feed = minidom.parseString(response.content).firstChild
self.assertEqual(feed.nodeName, 'feed')
- self.assertEqual(feed.getAttribute('xmlns'), 'http://www.w3.org/2005/Atom')
- self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'rights', 'category', 'author'])
+ self.assertEqual(feed.getAttribute('xmlns'),
+ 'http://www.w3.org/2005/Atom')
+ self.assertChildNodes(feed, [
+ 'title',
+ 'subtitle',
+ 'link',
+ 'id',
+ 'updated',
+ 'entry',
+ 'rights',
+ 'category',
+ 'author',
+ ])
+
for link in feed.getElementsByTagName('link'):
if link.getAttribute('rel') == 'self':
- self.assertEqual(link.getAttribute('href'), 'http://example.com/syndication/atom/')
+ self.assertEqual(link.getAttribute('href'),
+ 'http://example.com/syndication/atom/')
entries = feed.getElementsByTagName('entry')
self.assertEqual(len(entries), Entry.objects.count())
+
for entry in entries:
- self.assertChildNodes(entry, ['title', 'link', 'id', 'summary', 'category', 'updated', 'rights', 'author'])
+ self.assertChildNodes(entry, [
+ 'title',
+ 'link',
+ 'id',
+ 'summary',
+ 'category',
+ 'updated',
+ 'published',
+ 'rights',
+ 'author',
+ ])
summary = entry.getElementsByTagName('summary')[0]
self.assertEqual(summary.getAttribute('type'), 'html')
+ def test_atom_feed_published_and_updated_elements(self):
+ """
+ Test that the published and updated elements are not
+ the same and now adhere to RFC 4287.
+ """
+ response = self.client.get('/syndication/atom/')
+ feed = minidom.parseString(response.content).firstChild
+ entries = feed.getElementsByTagName('entry')
+
+ published = entries[0].getElementsByTagName('published')[0].firstChild.wholeText
+ updated = entries[0].getElementsByTagName('updated')[0].firstChild.wholeText
+
+ self.assertNotEqual(published, updated)
+
+ def test_latest_post_date(self):
+ """
+ Test that both the published and updated dates are
+ considered when determining the latest post date.
+ """
+ # this feed has a `published` element with the latest date
+ response = self.client.get('/syndication/atom/')
+ feed = minidom.parseString(response.content).firstChild
+ updated = feed.getElementsByTagName('updated')[0].firstChild.wholeText
+
+ d = Entry.objects.latest('published').published
+ ltz = tzinfo.LocalTimezone(d)
+ latest_published = rfc3339_date(d.replace(tzinfo=ltz))
+
+ self.assertEqual(updated, latest_published)
+
+ # this feed has am `updated` element with the latest date
+ response = self.client.get('/syndication/latest/')
+ feed = minidom.parseString(response.content).firstChild
+ updated = feed.getElementsByTagName('updated')[0].firstChild.wholeText
+
+ d = Entry.objects.exclude(pk=5).latest('updated').updated
+ ltz = tzinfo.LocalTimezone(d)
+ latest_updated = rfc3339_date(d.replace(tzinfo=ltz))
+
+ self.assertEqual(updated, latest_updated)
+
def test_custom_feed_generator(self):
response = self.client.get('/syndication/custom/')
feed = minidom.parseString(response.content).firstChild
self.assertEqual(feed.nodeName, 'feed')
self.assertEqual(feed.getAttribute('django'), 'rocks')
- self.assertChildNodes(feed, ['title', 'subtitle', 'link', 'id', 'updated', 'entry', 'spam', 'rights', 'category', 'author'])
+ self.assertChildNodes(feed, [
+ 'title',
+ 'subtitle',
+ 'link',
+ 'id',
+ 'updated',
+ 'entry',
+ 'spam',
+ 'rights',
+ 'category',
+ 'author',
+ ])
entries = feed.getElementsByTagName('entry')
self.assertEqual(len(entries), Entry.objects.count())
for entry in entries:
self.assertEqual(entry.getAttribute('bacon'), 'yum')
- self.assertChildNodes(entry, ['title', 'link', 'id', 'summary', 'ministry', 'rights', 'author', 'updated', 'category'])
+ self.assertChildNodes(entry, [
+ 'title',
+ 'link',
+ 'id',
+ 'summary',
+ 'ministry',
+ 'rights',
+ 'author',
+ 'updated',
+ 'published',
+ 'category',
+ ])
summary = entry.getElementsByTagName('summary')[0]
self.assertEqual(summary.getAttribute('type'), 'html')
@@ -233,7 +356,8 @@ def test_title_escaping(self):
link = item.getElementsByTagName('link')[0]
if link.firstChild.wholeText == 'http://example.com/blog/4/':
title = item.getElementsByTagName('title')[0]
- self.assertEqual(title.firstChild.wholeText, 'A &amp; B &lt; C &gt; D')
+ self.assertEqual(title.firstChild.wholeText,
+ 'A &amp; B &lt; C &gt; D')
def test_naive_datetime_conversion(self):
"""
@@ -245,7 +369,7 @@ def test_naive_datetime_conversion(self):
doc = minidom.parseString(response.content)
updated = doc.getElementsByTagName('updated')[0].firstChild.wholeText
- d = Entry.objects.latest('date').date
+ d = Entry.objects.latest('published').published
ltz = tzinfo.LocalTimezone(d)
latest = rfc3339_date(d.replace(tzinfo=ltz))
@@ -257,12 +381,13 @@ def test_aware_datetime_conversion(self):
"""
response = self.client.get('/syndication/aware-dates/')
doc = minidom.parseString(response.content)
- updated = doc.getElementsByTagName('updated')[0].firstChild.wholeText
- self.assertEqual(updated[-6:], '+00:42')
+ published = doc.getElementsByTagName('published')[0].firstChild.wholeText
+ self.assertEqual(published[-6:], '+00:42')
def test_feed_last_modified_time(self):
response = self.client.get('/syndication/naive-dates/')
- self.assertEqual(response['Last-Modified'], 'Thu, 03 Jan 2008 19:30:00 GMT')
+ self.assertEqual(response['Last-Modified'],
+ 'Tue, 26 Mar 2013 01:00:00 GMT')
# No last-modified when feed has no item_pubdate
response = self.client.get('/syndication/no_pubdate/')
@@ -276,7 +401,8 @@ def test_feed_url(self):
doc = minidom.parseString(response.content)
for link in doc.getElementsByTagName('link'):
if link.getAttribute('rel') == 'self':
- self.assertEqual(link.getAttribute('href'), 'http://example.com/customfeedurl/')
+ self.assertEqual(link.getAttribute('href'),
+ 'http://example.com/customfeedurl/')
def test_secure_urls(self):
"""
View
4 tests/syndication/urls.py
@@ -5,7 +5,8 @@
from . import feeds
-urlpatterns = patterns('django.contrib.syndication.views',
+urlpatterns = patterns(
+ 'django.contrib.syndication.views',
(r'^syndication/complex/(?P<foo>.*)/$', feeds.ComplexFeed()),
(r'^syndication/rss2/$', feeds.TestRss2Feed()),
(r'^syndication/rss2/guid_ispermalink_true/$',
@@ -15,6 +16,7 @@
(r'^syndication/rss091/$', feeds.TestRss091Feed()),
(r'^syndication/no_pubdate/$', feeds.TestNoPubdateFeed()),
(r'^syndication/atom/$', feeds.TestAtomFeed()),
+ (r'^syndication/latest/$', feeds.TestLatestFeed()),
(r'^syndication/custom/$', feeds.TestCustomFeed()),
(r'^syndication/naive-dates/$', feeds.NaiveDatesFeed()),
(r'^syndication/aware-dates/$', feeds.TZAwareDatesFeed()),
Something went wrong with that request. Please try again.