2010-01-28 21:46:18 +08:00
import datetime
from django . conf import settings
Fixed #14386, #8960, #10235, #10909, #10608, #13845, #14377 - standardize Site/RequestSite usage in various places.
Many thanks to gabrielhurley for putting most of this together. Also to
bmihelac, arthurk, qingfeng, hvendelbo, petr.pulc@s-cape.cz, Hraban for
reports and some initial patches.
The patch also contains some whitespace/PEP8 fixes.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@13980 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2010-10-04 22:20:47 +08:00
from django . contrib . sites . models import get_current_site
2010-01-28 21:46:18 +08:00
from django . core . exceptions import ImproperlyConfigured , ObjectDoesNotExist
2006-05-02 09:31:56 +08:00
from django . http import HttpResponse , Http404
2010-01-28 21:46:18 +08:00
from django . template import loader , Template , TemplateDoesNotExist , RequestContext
from django . utils import feedgenerator , tzinfo
from django . utils . encoding import force_unicode , iri_to_uri , smart_unicode
from django . utils . html import escape
2010-10-08 22:14:05 +08:00
def add_domain ( domain , url , secure = False ) :
2010-01-28 21:46:18 +08:00
if not ( url . startswith ( ' http:// ' )
or url . startswith ( ' https:// ' )
or url . startswith ( ' mailto: ' ) ) :
# 'url' must already be ASCII and URL-quoted, so no need for encoding
# conversions here.
2010-10-08 22:14:05 +08:00
if secure :
protocol = ' https '
else :
protocol = ' http '
url = iri_to_uri ( u ' %s :// %s %s ' % ( protocol , domain , url ) )
2010-01-28 21:46:18 +08:00
return url
class FeedDoesNotExist ( ObjectDoesNotExist ) :
pass
class Feed ( object ) :
feed_type = feedgenerator . DefaultFeed
title_template = None
description_template = None
def __call__ ( self , request , * args , * * kwargs ) :
try :
obj = self . get_object ( request , * args , * * kwargs )
except ObjectDoesNotExist :
raise Http404 ( ' Feed object does not exist. ' )
feedgen = self . get_feed ( obj , request )
response = HttpResponse ( mimetype = feedgen . mime_type )
feedgen . write ( response , ' utf-8 ' )
return response
def item_title ( self , item ) :
# Titles should be double escaped by default (see #6533)
return escape ( force_unicode ( item ) )
def item_description ( self , item ) :
return force_unicode ( item )
def item_link ( self , item ) :
try :
return item . get_absolute_url ( )
except AttributeError :
raise ImproperlyConfigured ( ' Give your %s class a get_absolute_url() method, or define an item_link() method in your Feed class. ' % item . __class__ . __name__ )
def __get_dynamic_attr ( self , attname , obj , default = None ) :
try :
attr = getattr ( self , attname )
except AttributeError :
return default
if callable ( attr ) :
# Check func_code.co_argcount rather than try/excepting the
# function and catching the TypeError, because something inside
# the function may raise the TypeError. This technique is more
# accurate.
if hasattr ( attr , ' func_code ' ) :
argcount = attr . func_code . co_argcount
else :
argcount = attr . __call__ . func_code . co_argcount
if argcount == 2 : # one argument is 'self'
return attr ( obj )
else :
return attr ( )
return attr
def feed_extra_kwargs ( self , obj ) :
"""
Returns an extra keyword arguments dictionary that is used when
initializing the feed generator .
"""
return { }
def item_extra_kwargs ( self , item ) :
"""
Returns an extra keyword arguments dictionary that is used with
the ` add_item ` call of the feed generator .
"""
return { }
def get_object ( self , request , * args , * * kwargs ) :
return None
def get_feed ( self , obj , request ) :
"""
Returns a feedgenerator . DefaultFeed object , fully populated , for
this feed . Raises FeedDoesNotExist for invalid parameters .
"""
Fixed #14386, #8960, #10235, #10909, #10608, #13845, #14377 - standardize Site/RequestSite usage in various places.
Many thanks to gabrielhurley for putting most of this together. Also to
bmihelac, arthurk, qingfeng, hvendelbo, petr.pulc@s-cape.cz, Hraban for
reports and some initial patches.
The patch also contains some whitespace/PEP8 fixes.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@13980 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2010-10-04 22:20:47 +08:00
current_site = get_current_site ( request )
2010-01-28 21:46:18 +08:00
link = self . __get_dynamic_attr ( ' link ' , obj )
2010-10-08 22:14:05 +08:00
link = add_domain ( current_site . domain , link , request . is_secure ( ) )
2010-01-28 21:46:18 +08:00
feed = self . feed_type (
title = self . __get_dynamic_attr ( ' title ' , obj ) ,
subtitle = self . __get_dynamic_attr ( ' subtitle ' , obj ) ,
link = link ,
description = self . __get_dynamic_attr ( ' description ' , obj ) ,
language = settings . LANGUAGE_CODE . decode ( ) ,
2010-10-08 22:14:05 +08:00
feed_url = add_domain (
current_site . domain ,
self . __get_dynamic_attr ( ' feed_url ' , obj ) or request . path ,
request . is_secure ( ) ,
) ,
2010-01-28 21:46:18 +08:00
author_name = self . __get_dynamic_attr ( ' author_name ' , obj ) ,
author_link = self . __get_dynamic_attr ( ' author_link ' , obj ) ,
author_email = self . __get_dynamic_attr ( ' author_email ' , obj ) ,
categories = self . __get_dynamic_attr ( ' categories ' , obj ) ,
feed_copyright = self . __get_dynamic_attr ( ' feed_copyright ' , obj ) ,
feed_guid = self . __get_dynamic_attr ( ' feed_guid ' , obj ) ,
ttl = self . __get_dynamic_attr ( ' ttl ' , obj ) ,
* * self . feed_extra_kwargs ( obj )
)
title_tmp = None
if self . title_template is not None :
try :
title_tmp = loader . get_template ( self . title_template )
except TemplateDoesNotExist :
pass
description_tmp = None
if self . description_template is not None :
try :
description_tmp = loader . get_template ( self . description_template )
except TemplateDoesNotExist :
pass
for item in self . __get_dynamic_attr ( ' items ' , obj ) :
if title_tmp is not None :
title = title_tmp . render ( RequestContext ( request , { ' obj ' : item , ' site ' : current_site } ) )
else :
title = self . __get_dynamic_attr ( ' item_title ' , item )
if description_tmp is not None :
description = description_tmp . render ( RequestContext ( request , { ' obj ' : item , ' site ' : current_site } ) )
else :
description = self . __get_dynamic_attr ( ' item_description ' , item )
2010-10-08 22:14:05 +08:00
link = add_domain (
current_site . domain ,
self . __get_dynamic_attr ( ' item_link ' , item ) ,
request . is_secure ( ) ,
)
2010-01-28 21:46:18 +08:00
enc = None
enc_url = self . __get_dynamic_attr ( ' item_enclosure_url ' , item )
if enc_url :
enc = feedgenerator . Enclosure (
url = smart_unicode ( enc_url ) ,
length = smart_unicode ( self . __get_dynamic_attr ( ' item_enclosure_length ' , item ) ) ,
mime_type = smart_unicode ( self . __get_dynamic_attr ( ' item_enclosure_mime_type ' , item ) )
)
author_name = self . __get_dynamic_attr ( ' item_author_name ' , item )
if author_name is not None :
author_email = self . __get_dynamic_attr ( ' item_author_email ' , item )
author_link = self . __get_dynamic_attr ( ' item_author_link ' , item )
else :
author_email = author_link = None
pubdate = self . __get_dynamic_attr ( ' item_pubdate ' , item )
if pubdate and not pubdate . tzinfo :
2010-03-15 23:25:39 +08:00
ltz = tzinfo . LocalTimezone ( pubdate )
pubdate = pubdate . replace ( tzinfo = ltz )
2010-01-28 21:46:18 +08:00
feed . add_item (
title = title ,
link = link ,
description = description ,
unique_id = self . __get_dynamic_attr ( ' item_guid ' , item , link ) ,
enclosure = enc ,
pubdate = pubdate ,
author_name = author_name ,
author_email = author_email ,
author_link = author_link ,
categories = self . __get_dynamic_attr ( ' item_categories ' , item ) ,
item_copyright = self . __get_dynamic_attr ( ' item_copyright ' , item ) ,
* * self . item_extra_kwargs ( item )
)
return feed
2005-11-12 11:44:53 +08:00
def feed ( request , url , feed_dict = None ) :
2010-01-28 21:46:18 +08:00
""" Provided for backwards compatibility. """
2011-01-13 22:51:34 +08:00
from django . contrib . syndication . feeds import Feed as LegacyFeed
2010-01-28 21:46:18 +08:00
import warnings
warnings . warn ( ' The syndication feed() view is deprecated. Please use the '
' new class based view API. ' ,
2010-10-11 20:20:07 +08:00
category = DeprecationWarning )
2010-01-28 21:46:18 +08:00
2005-11-12 11:44:53 +08:00
if not feed_dict :
2010-01-11 02:36:20 +08:00
raise Http404 ( " No feeds are registered. " )
2005-11-12 11:44:53 +08:00
try :
slug , param = url . split ( ' / ' , 1 )
except ValueError :
slug , param = url , ' '
try :
f = feed_dict [ slug ]
except KeyError :
2010-01-11 02:36:20 +08:00
raise Http404 ( " Slug %r isn ' t registered. " % slug )
2005-11-12 11:44:53 +08:00
2011-01-13 22:51:34 +08:00
# Backwards compatibility within the backwards compatibility;
# Feeds can be updated to be class-based, but still be deployed
# using the legacy feed view. This only works if the feed takes
# no arguments (i.e., get_object returns None). Refs #14176.
if not issubclass ( f , LegacyFeed ) :
instance = f ( )
instance . feed_url = getattr ( f , ' feed_url ' , None ) or request . path
instance . title_template = f . title_template or ( ' feeds/ %s _title.html ' % slug )
instance . description_template = f . description_template or ( ' feeds/ %s _description.html ' % slug )
return instance ( request )
2005-11-12 11:44:53 +08:00
try :
2007-07-12 13:29:32 +08:00
feedgen = f ( slug , request ) . get_feed ( param )
2010-01-28 21:46:18 +08:00
except FeedDoesNotExist :
2010-01-11 02:36:20 +08:00
raise Http404 ( " Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not. " % slug )
2005-11-12 11:44:53 +08:00
2005-11-13 02:32:12 +08:00
response = HttpResponse ( mimetype = feedgen . mime_type )
2005-11-12 11:44:53 +08:00
feedgen . write ( response , ' utf-8 ' )
return response
2010-01-28 21:46:18 +08:00