| 1 | from django.utils import feedgenerator |
| 2 | from django.models.core import sites |
| 3 | from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE |
| 4 | from django.core import template_loader |
| 5 | from django.core.template import Context |
| 6 | """ |
| 7 | This defines the parent classes for all the feed configuration objects. |
| 8 | """ |
| 9 | class RequiredFunctionError(Exception): |
| 10 | """ |
| 11 | I saw this somewhere and liked it. This gets thrown when a required feild is not defined in a base class |
| 12 | """ |
| 13 | def __init__(self,function): |
| 14 | Exception.__init__(self,"Function: %s is a required method and needs to be overridden" % function.__name__) |
| 15 | |
| 16 | |
| 17 | |
| 18 | class FeedConfiguration: |
| 19 | """ |
| 20 | This is the base Feed Configuration class, it maps with the Syntication Feed generator |
| 21 | """ |
| 22 | def __init__(self): |
| 23 | pass |
| 24 | |
| 25 | def get_feed(self): |
| 26 | """ |
| 27 | This return a feed generator, don't override this unless you know what your doing |
| 28 | """ |
| 29 | pass |
| 30 | ##### |
| 31 | ## Feed Options |
| 32 | ##### |
| 33 | def set_param_slug(self,param_slug): |
| 34 | raise RequiredFunctionError(self.set_param_slug) |
| 35 | |
| 36 | def get_slug(self): |
| 37 | raise RequiredFunctionError(self.get_slug) |
| 38 | |
| 39 | def _slug_getter(self): |
| 40 | return(self.get_slug()) |
| 41 | |
| 42 | slug = property(_slug_getter) |
| 43 | |
| 44 | def get_title(self): |
| 45 | raise RequiredFunctionError(self.get_title) |
| 46 | |
| 47 | def get_description(self): |
| 48 | return None |
| 49 | |
| 50 | def get_link(self): |
| 51 | raise RequiredFunctionError(self.get_link) |
| 52 | |
| 53 | |
| 54 | def get_language(self): |
| 55 | return None |
| 56 | |
| 57 | def get_items(self): |
| 58 | raise RequiredFunctionError(self.get_items) |
| 59 | |
| 60 | def set_current_item(self, item): |
| 61 | raise RequiredFunctionError(self.__init__) |
| 62 | |
| 63 | def get_item_title(self): |
| 64 | """ |
| 65 | The default function loads the template, rss/{slug}_title.html |
| 66 | Context: |
| 67 | obj: The current item |
| 68 | site: The current site |
| 69 | override this only if really needed. |
| 70 | """ |
| 71 | return None |
| 72 | |
| 73 | def get_item_description(self): |
| 74 | """ |
| 75 | The default function loads the template, rss/{slug}_description.html |
| 76 | Context: |
| 77 | obj: The current item |
| 78 | site: The current site |
| 79 | override this only if really needed. |
| 80 | """ |
| 81 | return None |
| 82 | |
| 83 | def get_item_link(self): |
| 84 | raise RequiredFunctionError(self.get_link) |
| 85 | |
| 86 | def get_item_author_email(self): |
| 87 | return None |
| 88 | |
| 89 | def get_item_author_name(self): |
| 90 | return None |
| 91 | |
| 92 | def get_item_pub_date(self): |
| 93 | """ |
| 94 | Returns: datetime.datetime |
| 95 | """ |
| 96 | return None |
| 97 | |
| 98 | def get_item_comments(self): |
| 99 | return None |
| 100 | |
| 101 | def get_item_unique_id(self): |
| 102 | return None |
| 103 | |
| 104 | def get_item_enclosure(self): |
| 105 | """ |
| 106 | returns: dict{url,mime_type,length} |
| 107 | """ |
| 108 | return None |
| 109 | |
| 110 | def get_item_categories(self): |
| 111 | return None |
| 112 | |
| 113 | class RssConfiguration(FeedConfiguration): |
| 114 | def __init__(self,Generator_Class=feedgenerator.DefaultRssFeed): |
| 115 | FeedConfiguration.__init__(self) |
| 116 | self.generator = Generator_Class |
| 117 | |
| 118 | def get_feed(self, param_slug=None): |
| 119 | """ |
| 120 | Returns a utils.feedgenerator.DefaultRssFeed object, fully populated, |
| 121 | representing this FeedConfiguration. |
| 122 | """ |
| 123 | current_site = sites.get_current() |
| 124 | |
| 125 | # Set the param slug |
| 126 | self.set_param_slug(param_slug) |
| 127 | |
| 128 | # Geth the feed generator object |
| 129 | f = self._get_feed_generator_object() |
| 130 | |
| 131 | # Get the feed's slug |
| 132 | slug = self.get_slug() |
| 133 | |
| 134 | |
| 135 | # Get the feed's items |
| 136 | for obj in self.get_items(): |
| 137 | # Set the current item so that the object can record it |
| 138 | self.set_current_item(obj) |
| 139 | |
| 140 | # Retrieve the current item's link |
| 141 | link = self.get_item_link() |
| 142 | if not link.startswith('http://'): |
| 143 | link = u'http://%s%s' % (current_site.domain, link) |
| 144 | |
| 145 | |
| 146 | # Get the item's title |
| 147 | title = self.get_item_title() |
| 148 | # If the title returns None (default action), |
| 149 | if title == None: |
| 150 | # Generate it with the rss title template for this feed |
| 151 | title_template = template_loader.get_template('rss/%s_title' % slug) |
| 152 | title = title_template.render(Context({'obj': obj, 'site': current_site})).decode('utf-8') |
| 153 | |
| 154 | # Get the item's description |
| 155 | description = self.get_item_description() |
| 156 | # If the description is None, |
| 157 | if description == None: |
| 158 | # Generate it with the rss description template for this feed |
| 159 | description_template = template_loader.get_template('rss/%s_description' % slug) |
| 160 | description = description_template.render(Context({'obj': obj, 'site': current_site})).decode('utf-8') |
| 161 | |
| 162 | # Init the enc variable |
| 163 | enc = None |
| 164 | # Get the item's enclosure data |
| 165 | enc_data = self.get_item_enclosure() |
| 166 | # If the enclosure data is not null |
| 167 | if enc_data: |
| 168 | # Create an Enclosure object with that data |
| 169 | enc = feedgenerator.Enclosure(enc_data['url'].decode('utf-8'), |
| 170 | (enc_data['length'] and str(enc_data['length']).decode('utf-8') or ''), |
| 171 | enc_data['mime_type'].decode('utf-8')) |
| 172 | |
| 173 | # Add the current item's data to the feed |
| 174 | f.add_item( |
| 175 | title = title, |
| 176 | description = description, |
| 177 | link = link, |
| 178 | unique_id = link, |
| 179 | enclosure = enc, |
| 180 | pubdate = self.get_item_pub_date(), |
| 181 | author_email= self.get_item_author_email(), |
| 182 | author_name = self.get_item_author_name(), |
| 183 | comments = self.get_item_comments(), |
| 184 | categories = self.get_item_categories(), |
| 185 | ) |
| 186 | return f |
| 187 | |
| 188 | def _get_feed_generator_object(self): |
| 189 | current_site = sites.get_current() |
| 190 | link = self.get_link().decode() |
| 191 | if not link.startswith('http://'): |
| 192 | link = u'http://%s%s' % (current_site.domain, link) |
| 193 | |
| 194 | return self.generator( |
| 195 | title = self.get_title(), |
| 196 | link = link, |
| 197 | description = self.get_description(), |
| 198 | language = LANGUAGE_CODE.decode(), |
| 199 | ) |
| 200 | |
| 201 | |
| 202 | def register_feed_modules(module_list): |
| 203 | """ |
| 204 | This function takes a list of module names and registers all the FeedConfiguration objects within that module |
| 205 | """ |
| 206 | import types |
| 207 | from django.core import rss |
| 208 | for module_name, attrs in module_list: |
| 209 | try: |
| 210 | # Load the module |
| 211 | module = __import__(module_name,'','',['']) |
| 212 | # loop over each item in the module, |
| 213 | for name,value in module.__dict__.items(): |
| 214 | # If the item in the module is a subclass of FeedConfiguration |
| 215 | if type(value) == types.ClassType and value != FeedConfiguration and issubclass(value,FeedConfiguration): |
| 216 | # if attrs is not None, init the class with the attrs |
| 217 | if attrs != None: |
| 218 | feed_config = value(**attrs) |
| 219 | # otherwise init it without it |
| 220 | else: |
| 221 | feed_config = value() |
| 222 | |
| 223 | # call the register feed function |
| 224 | rss.register_feed(feed_config) |
| 225 | except ImportError,e: |
| 226 | raise e |