Quantcast
Channel: Insert un-escaped html into rss feed made in django - Stack Overflow
Viewing all articles
Browse latest Browse all 7

Insert un-escaped html into rss feed made in django

$
0
0

I'm trying to use django to create a podcast rss feed using feedgenerator.Rss201rev2FeedAs a feed generator, it works somewhat the opposite to BeautifulSoup: putting info into appropriate xml tags

It's working well, except I'd like to not escape all the html

In particular, I'd like the <itunes:summary> value of the rss feed to appear like this:<itunes:summary><![CDATA[Link to <a href="http://www.website.com">the website</a>]]></itunes:summary>as per the Apple spec

If I were rendering html in a normal view, I could use the |safe filter in the html template. I need something similar now, to selectively prevent < being escaped in the rss feed.

That is, I need the rss to appear with <![CDATA[...]] rather than escaping to &lt;![CDATA[...]]&gt;

However, it seems Django "Django autoescapes special characters in RSS feeds (or any XML for that matter) no matter what, regardless of whether you pass it through the safe filter or not" (see this 2009 question)

No luck so far:

Therefore, attempts to use mark_safe thus far have proved useless.

I'm also unsure how to interpret one idea to pass "autoescape=False to the render() calls in django.contrib.syndication.feeds".

The suggestion to add , escape=False into the addQuickElement comment returned an error

 handler.addQuickElement(u'itunes:summary',item['summary'], escape=False) TypeError: addQuickElement() got an unexpected keyword argument 'escape'

It's an old issue, but I can't find any solution so far.

Anybody know a neat way to get <![CDATA[... to appear in the final feed, rather than escaping to &lt;![CDATA[...?


EDIT:Here's the code in current form as when I posted this question (I haven't yet tried incorporating @Lego's answer)

import mimetypesfrom django.conf import settingsfrom django.contrib.syndication.views import Feed# For customising the feedfrom django.utils.feedgenerator import Rss201rev2Feedfrom django.utils import feedgenerator# see also https://github.com/blancltd/blanc-basic-podcast/blob/master/blanc_basic_podcast/podcast/itunesfeed.py# and https://github.com/aneumeier/feeds/blob/master/feeds/rss.py# and https://github.com/blancltd/blanc-basic-podcast/blob/master/blanc_basic_podcast/podcast/feeds.py# and https://docs.djangoproject.com/en/1.7/ref/contrib/syndication/#custom-feed-generatorsfrom django.contrib.auth.models import Userfrom django.shortcuts import get_object_or_404from django.utils.translation import ugettext_lazy as _from django.contrib.sites.models import Sitefrom audiotracks.models import get_track_model, PlaylistTrack = get_track_model()ITEMS_PER_FEED = getattr(settings, 'AUDIOTRACKS_PODCAST_LIMIT', 99)# MarkAdded @ToDo revisit that default maximum num. tracks per feedfrom django.core.urlresolvers import reverse, reverse_lazyfrom django_slack import slack_message########################################################################### try adapting code from https://github.com/CaptainHayashi/django-lass-uryplayer/blob/master/uryplayer/feeds.pyfrom django.utils.feedgenerator import Rss201rev2Feedfrom django.contrib.syndication.views import Feedfrom django.contrib.sites.models import Sitefrom django.db.models import permalink# from uryplayer.models import Podcastimport datetime# MarkAdded in attempt to have un-escaped <![CDATA[...]]from django.utils.safestring import mark_safe# from https://stackoverflow.com/questions/275174/how-do-i-perform-html-decoding-encoding-using-python-djangotry:    from html.parser import HTMLParser  # py3except ImportError:    from HTMLParser import HTMLParser  # py2unescape = HTMLParser().unescape# print(unescape("&gt;"))# That proved useless so farclass iTunesPodcastsFeedGenerator(Rss201rev2Feed):    def rss_attributes(self):        return {u"version": self._version, u"xmlns:atom": u"http://www.w3.org/2005/Atom", u'xmlns:itunes': u'http://www.itunes.com/dtds/podcast-1.0.dtd'}    def add_root_elements(self, handler):        super(iTunesPodcastsFeedGenerator, self).add_root_elements(handler)        handler.addQuickElement(u'itunes:subtitle', self.feed['subtitle'])        handler.addQuickElement(u'itunes:author', self.feed['author_name'])        # handler.addQuickElement(u'itunes:summary', mark_safe(self.feed['description']))        handler.addQuickElement(u'itunes:summary', unescape(mark_safe(self.feed['description'])))        # handler.addQuickElement(u'itunes:image', self.feed['iTunes_image_url'])        handler.addQuickElement('itunes:image', '' , { 'href' : self.feed['iTunes_image_url']})        # that's from https://gitorious.org/podjango/podjango/commit/621857be0a3d7c44f1925c7daf471c38ea62c180?diffmode=sidebyside        handler.addQuickElement(u'itunes:explicit', self.feed['iTunes_explicit'])        handler.startElement(u"itunes:owner", {})        handler.addQuickElement(u'itunes:name', self.feed['iTunes_name'])        handler.addQuickElement(u'itunes:email', self.feed['iTunes_email'])        handler.endElement(u"itunes:owner")        # @ToDo: add categories    def add_item_elements(self,  handler, item):        super(iTunesPodcastsFeedGenerator, self).add_item_elements(handler, item)        handler.addQuickElement(u'itunes:summary', unescape(item['summary']))        handler.addQuickElement(u'itunes:explicit',item['explicit'])        # handler.addQuickElement(u'itunes:image', item['iTunes_image_url'])        handler.addQuickElement(u'itunes:image', '' , { 'href' : self.feed['iTunes_image_url']})    # def __unicode__(self):    #     return unicode(self.order_num)class iTunesPodcastPost():    def __init__(self, podcast): # note: podcast here = Track for me        self.id = podcast.id        # self.date_submitted = podcast.date_submitted        self.pub_date = podcast.pub_date        self.title = podcast.title if podcast.title else "Track"        self.summary = unescape(podcast.description) if podcast.description else "Cool thing"        # self.description = mark_safe("<![CDATA[%s]]>" % (podcast.description)) if podcast.description else ""        self.description = podcast.description if podcast.description else "Cool thing"        self.enclosure_url = podcast.awe_url # defined in models.py        self.enclosure_length = podcast.size if podcast.size else 1 # u'unkown duration'        self.enclosure_mime_type = u'audio/mpeg' # @ToDo generalise once we have other types        self.explicit = u'yes' if podcast.explicit else u'no'        self.url = podcast.get_absolute_url        self.iTunes_image_url = podcast.main_image_url # if podcast.main_image_url else 'http://fun.com'        self.length = podcast.time_duration if podcast.time_duration else 11 # "TBD"        self.user_id = podcast.user_id        self.user = User.objects.get(id = podcast.user_id)        self.slug = podcast.slug        self.duration = podcast.time_duration if podcast.time_duration else "5:00" # "Duration TBC"        # if categories:        #     categories = [to_unicode(c) for c in categories]        # see https://docs.djangoproject.com/en/1.7/_modules/django/utils/feedgenerator/#SyndicationFeed.add_root_elements    def __unicode__(self):        return self.title    def get_absolute_url(self):        # return "%s" % self.url()        # user = User.objects.get(id=self.user_id)        return reverse('track_detail', args=[self.user.username, self.slug]) class iTunesPodcastsFeed(Feed):"""    A feed of podcasts for iTunes and other compatible podcatchers.    Based on https://github.com/CaptainHayashi/django-lass-uryplayer/blob/master/uryplayer/feeds.py"""    def get_object(self, request, username, playlist_slug):        self.request = request        # return get_object_or_404(User, username=username)        user = get_object_or_404(User, username=username)        return get_object_or_404(Playlist, user_id=user.id, slug=playlist_slug)    def link(self, playlist):        # return self.request.build_absolute_uri("/@%s/" % user.username)        user = User.objects.get(id=playlist.user_id)        return reverse('playlist_index', args=[user.username, playlist.slug])    def title(self, playlist):        return playlist.title    # description_template = mark_safe("defaults/playlist_description_missing.html")    # not using that    def description(self, playlist):        if playlist.description:            return playlist.description            # return mark_safe("<![CDATA[%s]]>" % (playlist.description))            # No, I won't wrap in CDATA until I can avoid escaping the "<" signs here        else:            return "[Auto text] The creator has not written a description."            # return render_to_string("defaults/playlist_description_missing.txt")            # pass    def iTunes_image_url(self, obj): # TypeError: coercing to Unicode: need string or buffer, instancemethod found        if obj.main_image_url:            return unicode(obj.main_image_url) # obj.main_image_url        else:            return u'https://dl.dropboxusercontent.com/u/16441973/publicstatic/img/playlist-icon.png'    # author_name = 'University Radio York'    # modified from https://github.com/aneumeier/feeds/blob/master/feeds/rss.py    def author_name(self, obj): # obj = playlist"""        Return the author for this feed.        The feed is in `obj`, provided by `get_object`"""        if obj.author:            return u"%s" % obj.author        else:            return 'Playlist created by %s' % (obj.user.username)    def subtitle(self, obj): # obj = playlist"""        Return the author for this feed.        The feed is in `obj`, provided by `get_object`"""        if obj.subtitle:            return u"%s" % obj.author        else:            return '%s created in 2015' % (obj.title)    # def summary(self, obj):    #     return obj.description    # @ToDo: finish adapting rest of this from the hard-coded URY values to actual values for my implementation    iTunes_name = u'Hard-coded iTunes name for now'    iTunes_email = u'm@rkmoriarty.com'    # @ToDo: make dynamic, not hard-coded    iTunes_explicit = u'no'    feed_type = iTunesPodcastsFeedGenerator    feed_copyright = "Copyright 1967-%s University Radio York" % datetime.date.today().year    def feed_extra_kwargs(self, playlist):        extra = {}        extra['iTunes_name'] = self.iTunes_name        extra['iTunes_email'] = self.iTunes_email        # extra['iTunes_image_url'] = self.iTunes_image_url        def get_image(self, playlist):            if playlist.main_image_url:                return playlist.main_image_url            else:                return "https://dl.dropboxusercontent.com/u/16441973/publicstatic/img/rss_playlist_icon_placeholder.png"                # @ToDo: replace with Awesound logo            # return render_to_string("defaults/playlist_description_missing.txt")            # pass        extra['iTunes_image_url'] = get_image(self, playlist)        extra['iTunes_explicit'] = self.iTunes_explicit        return extra    def items(self, playlist):"""        Returns a list of items to publish in this feed."""        posts = playlist.tracks.all().order_by('-pub_date').order_by("-created_at")[:99]        posts = [iTunesPodcastPost(item) for item in posts]        return posts    def item_extra_kwargs(self, item):        return {'summary':unescape(mark_safe(item.description)), 'explicit':item.explicit,   'iTunes_image_url':item.iTunes_image_url}            # was summary: item.summary    # MarkAdded    def item_link(self, item):        # return item.enclosure_length        if item.user_id:            # we have a normal track created by a user            # user = User.objects.get(id = item.user_id)            return reverse('track_detail', args=[item.user.username, item.slug])        else:            # we have a funny track without a user, e.g., created via command line            return 'Exception:TrackWithoutUser'    def item_pubdate(self, item):        return item.pub_date    def item_enclosure_url(self, item):        return item.enclosure_url    def item_enclosure_length(self, item):        # return item.enclosure_length        return item.length    def item_enclosure_mime_type(self, item):        # return item.enclosure_mime_type        return 'audio/mpeg' # @ToDo: make dynamic    def item_description(self, item):        # return item.summary        if item.description:            return unescape(mark_safe(item.description))        else:            return "User has not written a description. This is an automatic message"# current_site = Site.objects.get_current()current_site = 'https://greatsite.com'iTunes_feed = iTunesPodcastsFeed()### the above will be called if both username and playlist_slug are deteced in the url### there are two older methods to handle other situationsclass AllTracks(Feed):    #    # working old method, not relevant to html escaping question    #class UserTracks(AllTracks):    #    # working old method, not relevant to my question    #all_tracks = AllTracks()user_tracks = UserTracks()### note, both of those are also subject to full html escaping alsodef choose_feed(request, *args, **kwargs):"""    Pick up the user feed or the global feed depending on whether or not the    URL contains a username parameter"""    # feed = user_tracks if 'username' in kwargs else all_tracks    if 'username' in kwargs:        if 'playlist_slug' in kwargs:            # feed = podcast_feed              slug = kwargs['playlist_slug']            feed = iTunes_feed            if request.user:                user = request.user                slack_message('slackmessages/playlist_feed.slack', { #django_slack/slackmessages/'playlist': Playlist.objects.get(slug=slug),'user':user,                    })        else:            feed = user_tracks    else:        feed = all_tracks         return feed.__call__(request, *args, **kwargs)

Viewing all articles
Browse latest Browse all 7

Latest Images

Trending Articles





Latest Images