2008-08-06 01:38:49 +08:00
from datetime import datetime , timedelta
2005-11-12 11:44:53 +08:00
from django . core . exceptions import ImproperlyConfigured , ObjectDoesNotExist
2008-07-22 11:24:09 +08:00
from django . template import loader , Template , TemplateDoesNotExist
2007-07-12 13:29:32 +08:00
from django . contrib . sites . models import Site , RequestSite
2005-11-12 11:44:53 +08:00
from django . utils import feedgenerator
2008-08-06 01:38:49 +08:00
from django . utils . tzinfo import FixedOffset
2007-07-08 01:15:54 +08:00
from django . utils . encoding import smart_unicode , iri_to_uri
2008-03-20 06:34:40 +08:00
from django . conf import settings
from django . template import RequestContext
2005-11-12 11:44:53 +08:00
def add_domain ( domain , url ) :
2008-02-01 06:31:38 +08:00
if not ( url . startswith ( ' http:// ' ) or url . startswith ( ' https:// ' ) ) :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
# 'url' must already be ASCII and URL-quoted, so no need for encoding
# conversions here.
2007-07-08 01:15:54 +08:00
url = iri_to_uri ( u ' http:// %s %s ' % ( domain , url ) )
2005-11-12 11:44:53 +08:00
return url
class FeedDoesNotExist ( ObjectDoesNotExist ) :
pass
2006-06-08 13:00:13 +08:00
class Feed ( object ) :
2005-11-12 11:44:53 +08:00
item_pubdate = None
item_enclosure_url = None
feed_type = feedgenerator . DefaultFeed
2006-06-27 07:19:03 +08:00
title_template = None
description_template = None
2005-11-12 11:44:53 +08:00
2007-07-12 13:29:32 +08:00
def __init__ ( self , slug , request ) :
2005-11-12 11:44:53 +08:00
self . slug = slug
2007-07-12 13:29:32 +08:00
self . request = request
self . feed_url = request . path
2006-06-27 07:19:03 +08:00
self . title_template_name = self . title_template or ( ' feeds/ %s _title.html ' % slug )
self . description_template_name = self . description_template or ( ' feeds/ %s _description.html ' % slug )
2005-11-12 11:44:53 +08:00
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__
2005-11-14 13:15:40 +08:00
def __get_dynamic_attr ( self , attname , obj , default = None ) :
try :
attr = getattr ( self , attname )
except AttributeError :
return default
2005-11-12 11:44:53 +08:00
if callable ( attr ) :
2006-02-19 04:34:14 +08:00
# 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'
2005-11-12 11:44:53 +08:00
return attr ( obj )
2006-02-19 04:34:14 +08:00
else :
2005-11-12 11:44:53 +08:00
return attr ( )
return attr
2008-03-18 23:40:27 +08:00
def get_object ( self , bits ) :
return None
2005-11-12 11:44:53 +08:00
def get_feed ( self , url = None ) :
"""
Returns a feedgenerator . DefaultFeed object , fully populated , for
this feed . Raises FeedDoesNotExist for invalid parameters .
"""
if url :
2008-03-18 23:40:27 +08:00
bits = url . split ( ' / ' )
2005-11-12 11:44:53 +08:00
else :
2008-03-18 23:40:27 +08:00
bits = [ ]
try :
obj = self . get_object ( bits )
except ObjectDoesNotExist :
raise FeedDoesNotExist
2005-11-12 11:44:53 +08:00
2007-07-12 13:29:32 +08:00
if Site . _meta . installed :
current_site = Site . objects . get_current ( )
else :
current_site = RequestSite ( self . request )
2008-08-12 04:49:19 +08:00
2005-11-12 11:44:53 +08:00
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 ) ,
2007-04-20 22:53:21 +08:00
subtitle = self . __get_dynamic_attr ( ' subtitle ' , obj ) ,
2005-11-12 11:44:53 +08:00
link = link ,
description = self . __get_dynamic_attr ( ' description ' , obj ) ,
2006-05-02 09:31:56 +08:00
language = settings . LANGUAGE_CODE . decode ( ) ,
2008-02-01 06:33:50 +08:00
feed_url = add_domain ( current_site . domain ,
self . __get_dynamic_attr ( ' feed_url ' , obj ) ) ,
2005-11-14 13:15:40 +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 ) ,
2006-06-19 09:38:06 +08:00
categories = self . __get_dynamic_attr ( ' categories ' , obj ) ,
2007-02-10 16:36:39 +08:00
feed_copyright = self . __get_dynamic_attr ( ' feed_copyright ' , obj ) ,
2007-07-10 20:33:55 +08:00
feed_guid = self . __get_dynamic_attr ( ' feed_guid ' , obj ) ,
2007-10-20 22:54:38 +08:00
ttl = self . __get_dynamic_attr ( ' ttl ' , obj ) ,
2005-11-12 11:44:53 +08:00
)
try :
2006-06-27 07:19:03 +08:00
title_tmp = loader . get_template ( self . title_template_name )
2005-11-12 11:44:53 +08:00
except TemplateDoesNotExist :
2006-06-27 07:19:03 +08:00
title_tmp = Template ( ' {{ obj }} ' )
2005-11-12 11:44:53 +08:00
try :
2006-06-27 07:19:03 +08:00
description_tmp = loader . get_template ( self . description_template_name )
2005-11-12 11:44:53 +08:00
except TemplateDoesNotExist :
2006-06-27 07:19:03 +08:00
description_tmp = Template ( ' {{ obj }} ' )
2005-11-12 11:44:53 +08:00
for item in self . __get_dynamic_attr ( ' items ' , obj ) :
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 (
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
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 ) )
2005-11-12 11:44:53 +08:00
)
2005-11-14 13:15:40 +08:00
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
2008-08-06 01:38:49 +08:00
pubdate = self . __get_dynamic_attr ( ' item_pubdate ' , item )
2008-08-06 07:52:03 +08:00
if pubdate :
2008-08-06 07:53:52 +08:00
now = datetime . now ( )
utcnow = 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.
2008-08-06 07:52:03 +08:00
tzOffsetMinutes = sign * ( ( tzDifference . seconds / 60 + 15 ) / 30 ) * 30
tzOffset = timedelta ( minutes = tzOffsetMinutes )
pubdate = pubdate . replace ( tzinfo = FixedOffset ( tzOffset ) )
2008-08-06 01:38:49 +08:00
2005-11-12 11:44:53 +08:00
feed . add_item (
2008-03-20 06:34:40 +08:00
title = title_tmp . render ( RequestContext ( self . request , { ' obj ' : item , ' site ' : current_site } ) ) ,
2005-11-12 11:44:53 +08:00
link = link ,
2008-03-20 06:34:40 +08:00
description = description_tmp . render ( RequestContext ( self . request , { ' obj ' : item , ' site ' : current_site } ) ) ,
2007-07-10 20:33:55 +08:00
unique_id = self . __get_dynamic_attr ( ' item_guid ' , item , link ) ,
2005-11-12 11:44:53 +08:00
enclosure = enc ,
2008-08-06 01:38:49 +08:00
pubdate = pubdate ,
2005-11-14 13:15:40 +08:00
author_name = author_name ,
author_email = author_email ,
author_link = author_link ,
2006-06-19 09:38:06 +08:00
categories = self . __get_dynamic_attr ( ' item_categories ' , item ) ,
2007-02-10 16:36:39 +08:00
item_copyright = self . __get_dynamic_attr ( ' item_copyright ' , item ) ,
2005-11-12 11:44:53 +08:00
)
return feed