app/django/contrib/syndication/feeds.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
       
     2 from django.template import Context, loader, Template, TemplateDoesNotExist
       
     3 from django.contrib.sites.models import Site, RequestSite
       
     4 from django.utils import feedgenerator
       
     5 from django.utils.encoding import smart_unicode, iri_to_uri
       
     6 from django.conf import settings         
       
     7 from django.template import RequestContext
       
     8 
       
     9 def add_domain(domain, url):
       
    10     if not (url.startswith('http://') or url.startswith('https://')):
       
    11         # 'url' must already be ASCII and URL-quoted, so no need for encoding
       
    12         # conversions here.
       
    13         url = iri_to_uri(u'http://%s%s' % (domain, url))
       
    14     return url
       
    15 
       
    16 class FeedDoesNotExist(ObjectDoesNotExist):
       
    17     pass
       
    18 
       
    19 class Feed(object):
       
    20     item_pubdate = None
       
    21     item_enclosure_url = None
       
    22     feed_type = feedgenerator.DefaultFeed
       
    23     title_template = None
       
    24     description_template = None
       
    25 
       
    26     def __init__(self, slug, request):
       
    27         self.slug = slug
       
    28         self.request = request
       
    29         self.feed_url = request.path
       
    30         self.title_template_name = self.title_template or ('feeds/%s_title.html' % slug)
       
    31         self.description_template_name = self.description_template or ('feeds/%s_description.html' % slug)
       
    32 
       
    33     def item_link(self, item):
       
    34         try:
       
    35             return item.get_absolute_url()
       
    36         except AttributeError:
       
    37             raise ImproperlyConfigured, "Give your %s class a get_absolute_url() method, or define an item_link() method in your Feed class." % item.__class__.__name__
       
    38 
       
    39     def __get_dynamic_attr(self, attname, obj, default=None):
       
    40         try:
       
    41             attr = getattr(self, attname)
       
    42         except AttributeError:
       
    43             return default
       
    44         if callable(attr):
       
    45             # Check func_code.co_argcount rather than try/excepting the
       
    46             # function and catching the TypeError, because something inside
       
    47             # the function may raise the TypeError. This technique is more
       
    48             # accurate.
       
    49             if hasattr(attr, 'func_code'):
       
    50                 argcount = attr.func_code.co_argcount
       
    51             else:
       
    52                 argcount = attr.__call__.func_code.co_argcount
       
    53             if argcount == 2: # one argument is 'self'
       
    54                 return attr(obj)
       
    55             else:
       
    56                 return attr()
       
    57         return attr
       
    58 
       
    59     def get_object(self, bits):
       
    60         return None
       
    61 
       
    62     def get_feed(self, url=None):
       
    63         """
       
    64         Returns a feedgenerator.DefaultFeed object, fully populated, for
       
    65         this feed. Raises FeedDoesNotExist for invalid parameters.
       
    66         """
       
    67         if url:
       
    68             bits = url.split('/')
       
    69         else:
       
    70             bits = []
       
    71 
       
    72         try:
       
    73             obj = self.get_object(bits)
       
    74         except ObjectDoesNotExist:
       
    75             raise FeedDoesNotExist
       
    76 
       
    77         if Site._meta.installed:
       
    78             current_site = Site.objects.get_current()
       
    79         else:
       
    80             current_site = RequestSite(self.request)
       
    81 
       
    82         link = self.__get_dynamic_attr('link', obj)
       
    83         link = add_domain(current_site.domain, link)
       
    84 
       
    85         feed = self.feed_type(
       
    86             title = self.__get_dynamic_attr('title', obj),
       
    87             subtitle = self.__get_dynamic_attr('subtitle', obj),
       
    88             link = link,
       
    89             description = self.__get_dynamic_attr('description', obj),
       
    90             language = settings.LANGUAGE_CODE.decode(),
       
    91             feed_url = add_domain(current_site.domain,
       
    92                                   self.__get_dynamic_attr('feed_url', obj)),
       
    93             author_name = self.__get_dynamic_attr('author_name', obj),
       
    94             author_link = self.__get_dynamic_attr('author_link', obj),
       
    95             author_email = self.__get_dynamic_attr('author_email', obj),
       
    96             categories = self.__get_dynamic_attr('categories', obj),
       
    97             feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
       
    98             feed_guid = self.__get_dynamic_attr('feed_guid', obj),
       
    99             ttl = self.__get_dynamic_attr('ttl', obj),
       
   100         )
       
   101 
       
   102         try:
       
   103             title_tmp = loader.get_template(self.title_template_name)
       
   104         except TemplateDoesNotExist:
       
   105             title_tmp = Template('{{ obj }}')
       
   106         try:
       
   107             description_tmp = loader.get_template(self.description_template_name)
       
   108         except TemplateDoesNotExist:
       
   109             description_tmp = Template('{{ obj }}')
       
   110 
       
   111         for item in self.__get_dynamic_attr('items', obj):
       
   112             link = add_domain(current_site.domain, self.__get_dynamic_attr('item_link', item))
       
   113             enc = None
       
   114             enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
       
   115             if enc_url:
       
   116                 enc = feedgenerator.Enclosure(
       
   117                     url = smart_unicode(enc_url),
       
   118                     length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
       
   119                     mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
       
   120                 )
       
   121             author_name = self.__get_dynamic_attr('item_author_name', item)
       
   122             if author_name is not None:
       
   123                 author_email = self.__get_dynamic_attr('item_author_email', item)
       
   124                 author_link = self.__get_dynamic_attr('item_author_link', item)
       
   125             else:
       
   126                 author_email = author_link = None
       
   127             feed.add_item(
       
   128                 title = title_tmp.render(RequestContext(self.request, {'obj': item, 'site': current_site})),
       
   129                 link = link,
       
   130                 description = description_tmp.render(RequestContext(self.request, {'obj': item, 'site': current_site})),
       
   131                 unique_id = self.__get_dynamic_attr('item_guid', item, link),
       
   132                 enclosure = enc,
       
   133                 pubdate = self.__get_dynamic_attr('item_pubdate', item),
       
   134                 author_name = author_name,
       
   135                 author_email = author_email,
       
   136                 author_link = author_link,
       
   137                 categories = self.__get_dynamic_attr('item_categories', item),
       
   138                 item_copyright = self.__get_dynamic_attr('item_copyright', item),
       
   139             )
       
   140         return feed