From 62300b81cf7687d176af3b40aa6101942801292d Mon Sep 17 00:00:00 2001 From: Baptiste Mispelon Date: Fri, 26 Apr 2024 22:10:40 +0200 Subject: Fixed #12978 -- Added support for RSS feed stylesheets. --- docs/ref/contrib/syndication.txt | 123 +++++++++++++++++++++++++++++++++++++-- docs/ref/utils.txt | 46 ++++++++++++++- 2 files changed, 162 insertions(+), 7 deletions(-) (limited to 'docs/ref') diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt index d9672c5b00..d0a3cc41f7 100644 --- a/docs/ref/contrib/syndication.txt +++ b/docs/ref/contrib/syndication.txt @@ -596,6 +596,24 @@ This example illustrates all possible attributes and methods for a ttl = 600 # Hard-coded Time To Live. + # STYLESHEETS -- Optional. To set, provide one of the following three. + # The framework looks for them in this order. + + def stylesheets(self, obj): + """ + Takes the object returned by get_object() and returns the feed's + stylesheets (as URL strings or as Stylesheet instances). + """ + + def stylesheets(self): + """ + Returns the feed's stylesheets (as URL strings or Stylesheet + instances). + """ + + # Hardcoded stylesheets. + stylesheets = ["/stylesheet1.xsl", "stylesheet2.xsl"] + # ITEMS -- One of the following three is required. The framework looks # for them in this order. @@ -961,16 +979,26 @@ They share this interface: * ``feed_copyright`` * ``feed_guid`` * ``ttl`` + * ``stylesheets`` Any extra keyword arguments you pass to ``__init__`` will be stored in ``self.feed`` for use with `custom feed generators`_. - All parameters should be strings, except ``categories``, which should be a - sequence of strings. Beware that some control characters - are `not allowed `_ - in XML documents. If your content has some of them, you might encounter a + All parameters should be strings, except for two: + + * ``categories`` should be a sequence of strings. + * ``stylesheets`` should be a sequence of either strings or + :class:`~django.utils.feedgenerator.Stylesheet` instances. + + Beware that some control characters are + `not allowed `_ in + XML documents. If your content has some of them, you might encounter a :exc:`ValueError` when producing the feed. + .. versionchanged:: 5.2 + + The ``stylesheets`` argument was added. + :meth:`.SyndicationFeed.add_item` Add an item to the feed with the given parameters. @@ -1095,3 +1123,90 @@ For example, you might start implementing an iTunes RSS feed generator like so:: There's a lot more work to be done for a complete custom feed class, but the above example should demonstrate the basic idea. + +.. _feed-stylesheets: + +Feed stylesheets +---------------- + +.. versionadded:: 5.2 + +If you wish to have your RSS feed render nicely in a browser, you will need to +provide styling information for the XML file, typically in XSLT_ or CSS +formats. + +You can add this to your RSS feed by setting the ``stylesheets`` attribute on +the feed class. + +This can be a hardcoded URL:: + + from django.contrib.syndication.views import Feed + + + class FeedWithHardcodedStylesheet(Feed): + stylesheets = [ + "https://example.com/rss_stylesheet.xslt", + ] + +You can also use Django's static files system:: + + from django.contrib.syndication.views import Feed + from django.templatetags.static import static + + + class FeedWithStaticFileStylesheet(Feed): + stylesheets = [ + static("rss_styles.xslt"), + ] + +Another option is to have a view in your project that renders the XSLT +document. You can then link it like so:: + + from django.contrib.syndication.views import Feed + from django.urls import reverse_lazy + + + class FeedWithStylesheetView(Feed): + stylesheets = [ + reverse_lazy("your-custom-view-name"), + ] + +Django will normally try to guess the MIME type of the given URL based on its +extension, but if that fails you can specify it using the +:class:`~django.utils.feedgenerator.Stylesheet` class:: + + from django.contrib.syndication.views import Feed + from django.utils.feedgenerator import Stylesheet + + + class FeedWithHardcodedStylesheet(Feed): + stylesheets = [ + Stylesheet("https://example.com/rss_stylesheet", mimetype="text/xsl"), + ] + +Similarly, if you'd like to use a different ``media`` attribute than ``screen`` +(Django's default), you can use the +:class:`~django.utils.feedgenerator.Stylesheet` class again:: + + from django.contrib.syndication.views import Feed + from django.utils.feedgenerator import Stylesheet + + + class FeedWithHardcodedStylesheet(Feed): + stylesheets = [ + Stylesheet("https://example.com/rss_stylesheet.xslt", media="print"), + ] + +Any of these options can be combined when using multiple stylesheets:: + + from django.contrib.syndication.views import Feed + from django.utils.feedgenerator import Stylesheet + + + class MultiStylesheetFeed(Feed): + stylesheets = [ + "/stylesheet1.xsl", + Stylesheet("/stylesheet2.xsl"), + ] + +.. _xslt: https://developer.mozilla.org/en-US/docs/Web/XSLT/Transforming_XML_with_XSLT diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index 3e357cba17..9fb1e83e9e 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -331,6 +331,32 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004 See https://web.archive.org/web/20110514113830/http://diveintomark.org/archives/2004/05/28/howto-atom-id +``Stylesheet`` +-------------- + +.. versionadded:: 5.2 + +.. class:: Stylesheet(url, mimetype="", media="screen") + + Represents an RSS stylesheet. + + .. attribute:: url + + Required argument. The URL where the stylesheet is located. + + .. attribute:: mimetype + + An optional string containing the MIME type of the stylesheet. If not + specified, Django will attempt to guess it by using Python's + :py:func:`mimetypes.guess_type()`. Use ``mimetype=None`` if you don't + want your stylesheet to have a MIME type specified. + + .. attribute:: media + + An optional string which will be used as the ``media`` attribute of + the stylesheet. Defaults to ``"screen"``. Use ``media=None`` if you + don't want your stylesheet to have a ``media`` attribute. + ``SyndicationFeed`` ------------------- @@ -339,7 +365,7 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004 Base class for all syndication feeds. Subclasses should provide ``write()``. - .. method:: __init__(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs) + .. method:: __init__(title, link, description, language=None, author_email=None, author_name=None, author_link=None, subtitle=None, categories=None, feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, stylesheets=None, **kwargs) Initialize the feed with the given dictionary of metadata, which applies to the entire feed. @@ -347,8 +373,15 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004 Any extra keyword arguments you pass to ``__init__`` will be stored in ``self.feed``. - All parameters should be strings, except ``categories``, which should - be a sequence of strings. + All parameters should be strings, except for two: + + * ``categories`` should be a sequence of strings. + * ``stylesheets`` should be a sequence of either strings or + :class:`Stylesheet` instances. + + .. versionchanged:: 5.2 + + The ``stylesheets`` argument was added. .. method:: add_item(title, link, description, author_email=None, author_name=None, author_link=None, pubdate=None, comments=None, unique_id=None, categories=(), item_copyright=None, ttl=None, updateddate=None, enclosures=None, **kwargs) @@ -368,6 +401,13 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004 Add elements in the root (i.e. feed/channel) element. Called from ``write()``. + .. method:: add_stylesheets(self, handler) + + .. versionadded:: 5.2 + + Add stylesheet information to the document. + Called from ``write()``. + .. method:: item_attributes(item) Return extra attributes to place on each item (i.e. item/entry) -- cgit v1.3