PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/syndication/views.py

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