root / env / lib / python2.7 / site-packages / django / contrib / syndication / views.py @ 1a305335
History | View | Annotate | Download (7.44 KB)
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 |
from django.utils.timezone import is_naive |
10 |
|
11 |
def add_domain(domain, url, secure=False): |
12 |
protocol = 'https' if secure else 'http' |
13 |
if url.startswith('//'): |
14 |
# Support network-path reference (see #16753) - RSS requires a protocol
|
15 |
url = '%s:%s' % (protocol, url)
|
16 |
elif not (url.startswith('http://') |
17 |
or url.startswith('https://') |
18 |
or url.startswith('mailto:')): |
19 |
# 'url' must already be ASCII and URL-quoted, so no need for encoding
|
20 |
# conversions here.
|
21 |
url = iri_to_uri(u'%s://%s%s' % (protocol, domain, url))
|
22 |
return url
|
23 |
|
24 |
class FeedDoesNotExist(ObjectDoesNotExist): |
25 |
pass
|
26 |
|
27 |
|
28 |
class Feed(object): |
29 |
feed_type = feedgenerator.DefaultFeed |
30 |
title_template = None
|
31 |
description_template = None
|
32 |
|
33 |
def __call__(self, request, *args, **kwargs): |
34 |
try:
|
35 |
obj = self.get_object(request, *args, **kwargs)
|
36 |
except ObjectDoesNotExist:
|
37 |
raise Http404('Feed object does not exist.') |
38 |
feedgen = self.get_feed(obj, request)
|
39 |
response = HttpResponse(content_type=feedgen.mime_type) |
40 |
feedgen.write(response, 'utf-8')
|
41 |
return response
|
42 |
|
43 |
def item_title(self, item): |
44 |
# Titles should be double escaped by default (see #6533)
|
45 |
return escape(force_unicode(item))
|
46 |
|
47 |
def item_description(self, item): |
48 |
return force_unicode(item)
|
49 |
|
50 |
def item_link(self, item): |
51 |
try:
|
52 |
return item.get_absolute_url()
|
53 |
except AttributeError: |
54 |
raise ImproperlyConfigured('Give your %s class a get_absolute_url() method, or define an item_link() method in your Feed class.' % item.__class__.__name__) |
55 |
|
56 |
def __get_dynamic_attr(self, attname, obj, default=None): |
57 |
try:
|
58 |
attr = getattr(self, attname) |
59 |
except AttributeError: |
60 |
return default
|
61 |
if callable(attr): |
62 |
# Check func_code.co_argcount rather than try/excepting the
|
63 |
# function and catching the TypeError, because something inside
|
64 |
# the function may raise the TypeError. This technique is more
|
65 |
# accurate.
|
66 |
if hasattr(attr, 'func_code'): |
67 |
argcount = attr.func_code.co_argcount |
68 |
else:
|
69 |
argcount = attr.__call__.func_code.co_argcount |
70 |
if argcount == 2: # one argument is 'self' |
71 |
return attr(obj)
|
72 |
else:
|
73 |
return attr()
|
74 |
return attr
|
75 |
|
76 |
def feed_extra_kwargs(self, obj): |
77 |
"""
|
78 |
Returns an extra keyword arguments dictionary that is used when
|
79 |
initializing the feed generator.
|
80 |
"""
|
81 |
return {}
|
82 |
|
83 |
def item_extra_kwargs(self, item): |
84 |
"""
|
85 |
Returns an extra keyword arguments dictionary that is used with
|
86 |
the `add_item` call of the feed generator.
|
87 |
"""
|
88 |
return {}
|
89 |
|
90 |
def get_object(self, request, *args, **kwargs): |
91 |
return None |
92 |
|
93 |
def get_feed(self, obj, request): |
94 |
"""
|
95 |
Returns a feedgenerator.DefaultFeed object, fully populated, for
|
96 |
this feed. Raises FeedDoesNotExist for invalid parameters.
|
97 |
"""
|
98 |
current_site = get_current_site(request) |
99 |
|
100 |
link = self.__get_dynamic_attr('link', obj) |
101 |
link = add_domain(current_site.domain, link, request.is_secure()) |
102 |
|
103 |
feed = self.feed_type(
|
104 |
title = self.__get_dynamic_attr('title', obj), |
105 |
subtitle = self.__get_dynamic_attr('subtitle', obj), |
106 |
link = link, |
107 |
description = self.__get_dynamic_attr('description', obj), |
108 |
language = settings.LANGUAGE_CODE.decode(), |
109 |
feed_url = add_domain( |
110 |
current_site.domain, |
111 |
self.__get_dynamic_attr('feed_url', obj) or request.path, |
112 |
request.is_secure(), |
113 |
), |
114 |
author_name = self.__get_dynamic_attr('author_name', obj), |
115 |
author_link = self.__get_dynamic_attr('author_link', obj), |
116 |
author_email = self.__get_dynamic_attr('author_email', obj), |
117 |
categories = self.__get_dynamic_attr('categories', obj), |
118 |
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj), |
119 |
feed_guid = self.__get_dynamic_attr('feed_guid', obj), |
120 |
ttl = self.__get_dynamic_attr('ttl', obj), |
121 |
**self.feed_extra_kwargs(obj)
|
122 |
) |
123 |
|
124 |
title_tmp = None
|
125 |
if self.title_template is not None: |
126 |
try:
|
127 |
title_tmp = loader.get_template(self.title_template)
|
128 |
except TemplateDoesNotExist:
|
129 |
pass
|
130 |
|
131 |
description_tmp = None
|
132 |
if self.description_template is not None: |
133 |
try:
|
134 |
description_tmp = loader.get_template(self.description_template)
|
135 |
except TemplateDoesNotExist:
|
136 |
pass
|
137 |
|
138 |
for item in self.__get_dynamic_attr('items', obj): |
139 |
if title_tmp is not None: |
140 |
title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site})) |
141 |
else:
|
142 |
title = self.__get_dynamic_attr('item_title', item) |
143 |
if description_tmp is not None: |
144 |
description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site})) |
145 |
else:
|
146 |
description = self.__get_dynamic_attr('item_description', item) |
147 |
link = add_domain( |
148 |
current_site.domain, |
149 |
self.__get_dynamic_attr('item_link', item), |
150 |
request.is_secure(), |
151 |
) |
152 |
enc = None
|
153 |
enc_url = self.__get_dynamic_attr('item_enclosure_url', item) |
154 |
if enc_url:
|
155 |
enc = feedgenerator.Enclosure( |
156 |
url = smart_unicode(enc_url), |
157 |
length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)), |
158 |
mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item)) |
159 |
) |
160 |
author_name = self.__get_dynamic_attr('item_author_name', item) |
161 |
if author_name is not None: |
162 |
author_email = self.__get_dynamic_attr('item_author_email', item) |
163 |
author_link = self.__get_dynamic_attr('item_author_link', item) |
164 |
else:
|
165 |
author_email = author_link = None
|
166 |
|
167 |
pubdate = self.__get_dynamic_attr('item_pubdate', item) |
168 |
if pubdate and is_naive(pubdate): |
169 |
ltz = tzinfo.LocalTimezone(pubdate) |
170 |
pubdate = pubdate.replace(tzinfo=ltz) |
171 |
|
172 |
feed.add_item( |
173 |
title = title, |
174 |
link = link, |
175 |
description = description, |
176 |
unique_id = self.__get_dynamic_attr('item_guid', item, link), |
177 |
enclosure = enc, |
178 |
pubdate = pubdate, |
179 |
author_name = author_name, |
180 |
author_email = author_email, |
181 |
author_link = author_link, |
182 |
categories = self.__get_dynamic_attr('item_categories', item), |
183 |
item_copyright = self.__get_dynamic_attr('item_copyright', item), |
184 |
**self.item_extra_kwargs(item)
|
185 |
) |
186 |
return feed
|