2010-01-28 21:46:18 +08:00
import datetime
from django . conf import settings
from django . contrib . sites . models import Site , RequestSite
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
def add_domain ( domain , url ) :
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.
url = iri_to_uri ( u ' http:// %s %s ' % ( domain , url ) )
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 .
"""
if Site . _meta . installed :
current_site = Site . objects . get_current ( )
else :
current_site = RequestSite ( request )
link = self . __get_dynamic_attr ( ' link ' , obj )
link = add_domain ( current_site . domain , link )
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 ( ) ,
feed_url = add_domain ( current_site . domain ,
self . __get_dynamic_attr ( ' feed_url ' , obj ) or request . path ) ,
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 )
link = add_domain ( current_site . domain , self . __get_dynamic_attr ( ' item_link ' , item ) )
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 :
now = datetime . datetime . now ( )
utcnow = datetime . datetime . utcnow ( )
# Must always subtract smaller time from larger time here.
if utcnow > now :
sign = - 1
tzDifference = ( utcnow - now )
else :
sign = 1
tzDifference = ( now - utcnow )
# Round the timezone offset to the nearest half hour.
tzOffsetMinutes = sign * ( ( tzDifference . seconds / 60 + 15 ) / 30 ) * 30
tzOffset = datetime . timedelta ( minutes = tzOffsetMinutes )
pubdate = pubdate . replace ( tzinfo = tzinfo . FixedOffset ( tzOffset ) )
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. """
import warnings
warnings . warn ( ' The syndication feed() view is deprecated. Please use the '
' new class based view API. ' ,
category = PendingDeprecationWarning )
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
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