web/lib/django/contrib/syndication/views.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
     1 from django.contrib.syndication import feeds
     1 import datetime
       
     2 from django.conf import settings
       
     3 from django.contrib.sites.models import Site, RequestSite
       
     4 from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
     2 from django.http import HttpResponse, Http404
     5 from django.http import HttpResponse, Http404
       
     6 from django.template import loader, Template, TemplateDoesNotExist, RequestContext
       
     7 from django.utils import feedgenerator, tzinfo
       
     8 from django.utils.encoding import force_unicode, iri_to_uri, smart_unicode
       
     9 from django.utils.html import escape
       
    10 
       
    11 def add_domain(domain, url):
       
    12     if not (url.startswith('http://')
       
    13             or url.startswith('https://')
       
    14             or url.startswith('mailto:')):
       
    15         # 'url' must already be ASCII and URL-quoted, so no need for encoding
       
    16         # conversions here.
       
    17         url = iri_to_uri(u'http://%s%s' % (domain, url))
       
    18     return url
       
    19 
       
    20 class FeedDoesNotExist(ObjectDoesNotExist):
       
    21     pass
       
    22 
       
    23 
       
    24 class Feed(object):
       
    25     feed_type = feedgenerator.DefaultFeed
       
    26     title_template = None
       
    27     description_template = None
       
    28 
       
    29     def __call__(self, request, *args, **kwargs):
       
    30         try:
       
    31             obj = self.get_object(request, *args, **kwargs)
       
    32         except ObjectDoesNotExist:
       
    33             raise Http404('Feed object does not exist.')
       
    34         feedgen = self.get_feed(obj, request)
       
    35         response = HttpResponse(mimetype=feedgen.mime_type)
       
    36         feedgen.write(response, 'utf-8')
       
    37         return response
       
    38 
       
    39     def item_title(self, item):
       
    40         # Titles should be double escaped by default (see #6533)
       
    41         return escape(force_unicode(item))
       
    42 
       
    43     def item_description(self, item):
       
    44         return force_unicode(item)
       
    45 
       
    46     def item_link(self, item):
       
    47         try:
       
    48             return item.get_absolute_url()
       
    49         except AttributeError:
       
    50             raise ImproperlyConfigured('Give your %s class a get_absolute_url() method, or define an item_link() method in your Feed class.' % item.__class__.__name__)
       
    51 
       
    52     def __get_dynamic_attr(self, attname, obj, default=None):
       
    53         try:
       
    54             attr = getattr(self, attname)
       
    55         except AttributeError:
       
    56             return default
       
    57         if callable(attr):
       
    58             # Check func_code.co_argcount rather than try/excepting the
       
    59             # function and catching the TypeError, because something inside
       
    60             # the function may raise the TypeError. This technique is more
       
    61             # accurate.
       
    62             if hasattr(attr, 'func_code'):
       
    63                 argcount = attr.func_code.co_argcount
       
    64             else:
       
    65                 argcount = attr.__call__.func_code.co_argcount
       
    66             if argcount == 2: # one argument is 'self'
       
    67                 return attr(obj)
       
    68             else:
       
    69                 return attr()
       
    70         return attr
       
    71 
       
    72     def feed_extra_kwargs(self, obj):
       
    73         """
       
    74         Returns an extra keyword arguments dictionary that is used when
       
    75         initializing the feed generator.
       
    76         """
       
    77         return {}
       
    78 
       
    79     def item_extra_kwargs(self, item):
       
    80         """
       
    81         Returns an extra keyword arguments dictionary that is used with
       
    82         the `add_item` call of the feed generator.
       
    83         """
       
    84         return {}
       
    85 
       
    86     def get_object(self, request, *args, **kwargs):
       
    87         return None
       
    88 
       
    89     def get_feed(self, obj, request):
       
    90         """
       
    91         Returns a feedgenerator.DefaultFeed object, fully populated, for
       
    92         this feed. Raises FeedDoesNotExist for invalid parameters.
       
    93         """
       
    94         if Site._meta.installed:
       
    95             current_site = Site.objects.get_current()
       
    96         else:
       
    97             current_site = RequestSite(request)
       
    98 
       
    99         link = self.__get_dynamic_attr('link', obj)
       
   100         link = add_domain(current_site.domain, link)
       
   101 
       
   102         feed = self.feed_type(
       
   103             title = self.__get_dynamic_attr('title', obj),
       
   104             subtitle = self.__get_dynamic_attr('subtitle', obj),
       
   105             link = link,
       
   106             description = self.__get_dynamic_attr('description', obj),
       
   107             language = settings.LANGUAGE_CODE.decode(),
       
   108             feed_url = add_domain(current_site.domain,
       
   109                     self.__get_dynamic_attr('feed_url', obj) or request.path),
       
   110             author_name = self.__get_dynamic_attr('author_name', obj),
       
   111             author_link = self.__get_dynamic_attr('author_link', obj),
       
   112             author_email = self.__get_dynamic_attr('author_email', obj),
       
   113             categories = self.__get_dynamic_attr('categories', obj),
       
   114             feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
       
   115             feed_guid = self.__get_dynamic_attr('feed_guid', obj),
       
   116             ttl = self.__get_dynamic_attr('ttl', obj),
       
   117             **self.feed_extra_kwargs(obj)
       
   118         )
       
   119 
       
   120         title_tmp = None
       
   121         if self.title_template is not None:
       
   122             try:
       
   123                 title_tmp = loader.get_template(self.title_template)
       
   124             except TemplateDoesNotExist:
       
   125                 pass
       
   126 
       
   127         description_tmp = None
       
   128         if self.description_template is not None:
       
   129             try:
       
   130                 description_tmp = loader.get_template(self.description_template)
       
   131             except TemplateDoesNotExist:
       
   132                 pass
       
   133 
       
   134         for item in self.__get_dynamic_attr('items', obj):
       
   135             if title_tmp is not None:
       
   136                 title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
       
   137             else:
       
   138                 title = self.__get_dynamic_attr('item_title', item)
       
   139             if description_tmp is not None:
       
   140                 description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
       
   141             else:
       
   142                 description = self.__get_dynamic_attr('item_description', item)
       
   143             link = add_domain(current_site.domain, self.__get_dynamic_attr('item_link', item))
       
   144             enc = None
       
   145             enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
       
   146             if enc_url:
       
   147                 enc = feedgenerator.Enclosure(
       
   148                     url = smart_unicode(enc_url),
       
   149                     length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
       
   150                     mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
       
   151                 )
       
   152             author_name = self.__get_dynamic_attr('item_author_name', item)
       
   153             if author_name is not None:
       
   154                 author_email = self.__get_dynamic_attr('item_author_email', item)
       
   155                 author_link = self.__get_dynamic_attr('item_author_link', item)
       
   156             else:
       
   157                 author_email = author_link = None
       
   158 
       
   159             pubdate = self.__get_dynamic_attr('item_pubdate', item)
       
   160             if pubdate and not pubdate.tzinfo:
       
   161                 ltz = tzinfo.LocalTimezone(pubdate)
       
   162                 pubdate = pubdate.replace(tzinfo=ltz)
       
   163 
       
   164             feed.add_item(
       
   165                 title = title,
       
   166                 link = link,
       
   167                 description = description,
       
   168                 unique_id = self.__get_dynamic_attr('item_guid', item, link),
       
   169                 enclosure = enc,
       
   170                 pubdate = pubdate,
       
   171                 author_name = author_name,
       
   172                 author_email = author_email,
       
   173                 author_link = author_link,
       
   174                 categories = self.__get_dynamic_attr('item_categories', item),
       
   175                 item_copyright = self.__get_dynamic_attr('item_copyright', item),
       
   176                 **self.item_extra_kwargs(item)
       
   177             )
       
   178         return feed
       
   179 
     3 
   180 
     4 def feed(request, url, feed_dict=None):
   181 def feed(request, url, feed_dict=None):
       
   182     """Provided for backwards compatibility."""
       
   183     import warnings
       
   184     warnings.warn('The syndication feed() view is deprecated. Please use the '
       
   185                   'new class based view API.',
       
   186                   category=PendingDeprecationWarning)
       
   187 
     5     if not feed_dict:
   188     if not feed_dict:
     6         raise Http404, "No feeds are registered."
   189         raise Http404("No feeds are registered.")
     7 
   190 
     8     try:
   191     try:
     9         slug, param = url.split('/', 1)
   192         slug, param = url.split('/', 1)
    10     except ValueError:
   193     except ValueError:
    11         slug, param = url, ''
   194         slug, param = url, ''
    12 
   195 
    13     try:
   196     try:
    14         f = feed_dict[slug]
   197         f = feed_dict[slug]
    15     except KeyError:
   198     except KeyError:
    16         raise Http404, "Slug %r isn't registered." % slug
   199         raise Http404("Slug %r isn't registered." % slug)
    17 
   200 
    18     try:
   201     try:
    19         feedgen = f(slug, request).get_feed(param)
   202         feedgen = f(slug, request).get_feed(param)
    20     except feeds.FeedDoesNotExist:
   203     except FeedDoesNotExist:
    21         raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug
   204         raise Http404("Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug)
    22 
   205 
    23     response = HttpResponse(mimetype=feedgen.mime_type)
   206     response = HttpResponse(mimetype=feedgen.mime_type)
    24     feedgen.write(response, 'utf-8')
   207     feedgen.write(response, 'utf-8')
    25     return response
   208     return response
       
   209