Commit a269ea4f authored by Matt Deacalion Stevens's avatar Matt Deacalion Stevens Committed by Tim Graham
Browse files

Fixed #14656 -- Added 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`.
parent e1c737b6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+9 −3
Original line number Diff line number Diff line
@@ -43,9 +43,9 @@ class Feed(object):
            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 @@ class Feed(object):
                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 @@ class Feed(object):
                    'item_guid_is_permalink', item),
                enclosure = enc,
                pubdate = pubdate,
                updateddate = updateddate,
                author_name = author_name,
                author_email = author_email,
                author_link = author_link,
+22 −12
Original line number Diff line number Diff line
@@ -114,11 +114,11 @@ 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, **kwargs):
        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 +134,7 @@ class SyndicationFeed(object):
            '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,15 +192,20 @@ class SyndicationFeed(object):

    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]
        else:
            return datetime.datetime.now()
        latest_date = None
        date_keys = ('updateddate', 'pubdate')

        for item in self.items:
            for date_key in date_keys:
                item_date = item.get(date_key)
                if item_date:
                    if latest_date is None or item_date > latest_date:
                        latest_date = item_date

        return latest_date or datetime.datetime.now()

class Enclosure(object):
    "Represents an RSS enclosure"
@@ -349,8 +355,12 @@ class Atom1Feed(SyndicationFeed):
    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:
+24 −0
Original line number Diff line number Diff line
@@ -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.

+10 −5
Original line number Diff line number Diff line
@@ -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,9 @@ 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 ``pubdate`` or ``updateddate`` for all items in the
        feed. If no items have either of these attributes this returns the
        current date/time.

Enclosure
---------
Loading