Added winer doc file. Improved the docstrings for FeedView from the penfield version.
authorStephen Burrows <stephen.r.burrows@gmail.com>
Wed, 22 Jun 2011 02:10:04 +0000 (22:10 -0400)
committerStephen Burrows <stephen.r.burrows@gmail.com>
Wed, 22 Jun 2011 02:10:04 +0000 (22:10 -0400)
docs/contrib/intro.rst
docs/contrib/penfield.rst
docs/contrib/winer.rst [new file with mode: 0644]
philo/contrib/__init__.py
philo/contrib/winer/__init__.py
philo/contrib/winer/exceptions.py
philo/contrib/winer/middleware.py
philo/contrib/winer/models.py

index 3b97ecd..e833317 100644 (file)
@@ -9,5 +9,6 @@ Contrib apps
        shipherd
        sobol
        waldo
+       winer
 
 .. automodule:: philo.contrib
index d774dcb..87073b9 100644 (file)
@@ -27,18 +27,6 @@ Newsletters
 .. autoclass:: philo.contrib.penfield.models.NewsletterView
        :members:
 
-Abstract Syndication
-++++++++++++++++++++
-
-.. autoclass:: philo.contrib.penfield.models.FeedView
-       :members:
-
-.. automodule:: philo.contrib.penfield.exceptions
-       :members:
-
-.. automodule:: philo.contrib.penfield.middleware
-       :members:
-
 Template filters
 ++++++++++++++++
 
diff --git a/docs/contrib/winer.rst b/docs/contrib/winer.rst
new file mode 100644 (file)
index 0000000..4b8a670
--- /dev/null
@@ -0,0 +1,15 @@
+Winer
+=====
+
+.. automodule:: philo.contrib.winer
+
+.. automodule:: philo.contrib.winer.models
+
+       .. autoclass:: FeedView
+               :members:
+
+.. automodule:: philo.contrib.winer.exceptions
+       :members:
+
+.. automodule:: philo.contrib.winer.middleware
+       :members:
\ No newline at end of file
index d6c4be4..0cde6d5 100644 (file)
@@ -2,9 +2,10 @@
 """
 Following Python and Django’s “batteries included” philosophy, Philo includes a number of optional packages that simplify common website structures:
 
-* :mod:`~philo.contrib.penfield` — Basic philo syndication, and blog and newsletter management.
+* :mod:`~philo.contrib.penfield` — Basic blog and newsletter management.
 * :mod:`~philo.contrib.shipherd` — Powerful site navigation.
 * :mod:`~philo.contrib.sobol` — Custom web and database searches.
 * :mod:`~philo.contrib.waldo` — Custom authentication systems.
+* :mod:`~philo.contrib.winer` — Abstract framework for Philo-based syndication.
 
 """
\ No newline at end of file
index e69de29..83fb303 100644 (file)
@@ -0,0 +1,4 @@
+"""
+Winer provides the same API as `django's syndication Feed class <http://docs.djangoproject.com/en/dev/ref/contrib/syndication/#django.contrib.syndication.django.contrib.syndication.views.Feed>`_, adapted to a Philo-style :class:`~philo.models.nodes.MultiView` for easy database management. Apps that need syndication can simply subclass :class:`~philo.contrib.winer.models.FeedView`, override a few methods, and start serving RSS and Atom feeds. See :class:`~philo.contrib.penfield.models.BlogView` for a concrete implementation example.
+
+"""
\ No newline at end of file
index 96b96ed..e2045f9 100644 (file)
@@ -1,3 +1,3 @@
 class HttpNotAcceptable(Exception):
-       """This will be raised if an Http-Accept header will not accept the feed content types that are available."""
+       """This will be raised in :meth:`.FeedView.get_feed_type` if an Http-Accept header will not accept any of the feed content types that are available."""
        pass
\ No newline at end of file
index a0cd649..89a5bd2 100644 (file)
@@ -1,11 +1,11 @@
 from django.http import HttpResponse
 from django.utils.decorators import decorator_from_middleware
 
-from philo.contrib.penfield.exceptions import HttpNotAcceptable
+from philo.contrib.winer.exceptions import HttpNotAcceptable
 
 
 class HttpNotAcceptableMiddleware(object):
-       """Middleware to catch :exc:`~philo.contrib.penfield.exceptions.HttpNotAcceptable` and return an :class:`HttpResponse` with a 406 response code. See :rfc:`2616`."""
+       """Middleware to catch :exc:`~philo.contrib.winer.exceptions.HttpNotAcceptable` and return an :class:`HttpResponse` with a 406 response code. See :rfc:`2616`."""
        def process_exception(self, request, exception):
                if isinstance(exception, HttpNotAcceptable):
                        return HttpResponse(status=406)
index 6f87801..5e85cc3 100644 (file)
@@ -22,12 +22,14 @@ except:
 
 class FeedView(MultiView):
        """
-       :class:`FeedView` handles a number of pages and related feeds for a single object such as a blog or newsletter. In addition to all other methods and attributes, :class:`FeedView` supports the same generic API as `django.contrib.syndication.views.Feed <http://docs.djangoproject.com/en/dev/ref/contrib/syndication/#django.contrib.syndication.django.contrib.syndication.views.Feed>`_.
+       :class:`FeedView` is an abstract model which handles a number of pages and related feeds for a single object such as a blog or newsletter. In addition to all other methods and attributes, :class:`FeedView` supports the same generic API as `django.contrib.syndication.views.Feed <http://docs.djangoproject.com/en/dev/ref/contrib/syndication/#django.contrib.syndication.django.contrib.syndication.views.Feed>`_.
        
        """
        #: The type of feed which should be served by the :class:`FeedView`.
        feed_type = models.CharField(max_length=50, choices=registry.choices, default=registry.get_slug(DEFAULT_FEED))
-       #: The suffix which will be appended to a page URL for a feed of its items. Default: "feed"
+       #: The suffix which will be appended to a page URL for a :attr:`feed_type` feed of its items. Default: "feed". Note that RSS and Atom feeds will always be available at ``<page_url>/rss`` and ``<page_url>/atom`` regardless of the value of this setting.
+       #:
+       #: .. seealso:: :meth:`get_feed_type`, :meth:`feed_patterns`
        feed_suffix = models.CharField(max_length=255, blank=False, default="feed")
        #: A :class:`BooleanField` - whether or not feeds are enabled.
        feeds_enabled = models.BooleanField(default=True)
@@ -39,17 +41,25 @@ class FeedView(MultiView):
        #: A :class:`ForeignKey` to a :class:`.Template` which will be used to render the description of each item in the feed if provided.
        item_description_template = models.ForeignKey(Template, blank=True, null=True, related_name="%(app_label)s_%(class)s_description_related")
        
-       #: The name of the context variable to be populated with the items managed by the :class:`FeedView`.
+       #: An attribute holding the name of the context variable to be populated with the items managed by the :class:`FeedView`. Default: "items"
        item_context_var = 'items'
-       #: The attribute on a subclass of :class:`FeedView` which will contain the main object of a feed (such as a :class:`Blog`.)
+       #: An attribute holding the name of the attribute on a subclass of :class:`FeedView` which will contain the main object of a feed (such as a :class:`~philo.contrib.penfield.models.Blog`.) Default: "object"
+       #:
+       #: Example::
+       #:
+       #:     class BlogView(FeedView):
+       #:         blog = models.ForeignKey(Blog)
+       #:         
+       #:         object_attr = 'blog'
+       #:         item_context_var = 'entries'
        object_attr = 'object'
        
-       #: A description of the feeds served by the :class:`FeedView`. This is a required part of the :class:`django.contrib.syndication.view.Feed` API.
+       #: An attribute holding a description of the feeds served by the :class:`FeedView`. This is a required part of the :class:`django.contrib.syndication.view.Feed` API.
        description = ""
        
        def feed_patterns(self, base, get_items_attr, page_attr, reverse_name):
                """
-               Given the name to be used to reverse this view and the names of the attributes for the function that fetches the objects, returns patterns suitable for inclusion in urlpatterns. In addition to ``base`` and ``base`` + :attr:`feed_suffix`, patterns will be provided for each registered feed type as ``base`` + ``slug``.
+               Given the name to be used to reverse this view and the names of the attributes for the function that fetches the objects, returns patterns suitable for inclusion in urlpatterns. In addition to ``base`` (which will serve the page at ``page_attr``) and ``base`` + :attr:`feed_suffix` (which will serve a :attr:`feed_type` feed), patterns will be provided for each registered feed type as ``base`` + ``slug``.
                
                :param base: The base of the returned patterns - that is, the subpath pattern which will reference the page for the items. The :attr:`feed_suffix` will be appended to this subpath.
                :param get_items_attr: A callable or the name of a callable on the :class:`FeedView` which will return an (``items``, ``extra_context``) tuple. This will be passed directly to :meth:`feed_view` and :meth:`page_view`.
@@ -59,11 +69,22 @@ class FeedView(MultiView):
                
                Example::
                
-                       @property
-                       def urlpatterns(self):
-                               urlpatterns = self.feed_patterns(r'^', 'get_all_entries', 'index_page', 'index')
-                               urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_day')
-                               return urlpatterns
+                       class BlogView(FeedView):
+                           blog = models.ForeignKey(Blog)
+                           entry_archive_page = models.ForeignKey(Page)
+                           
+                           @property
+                           def urlpatterns(self):
+                               urlpatterns = self.feed_patterns(r'^', 'get_all_entries', 'index_page', 'index')
+                               urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_day')
+                               return urlpatterns
+                           
+                           def get_entries_by_ymd(request, year, month, day, extra_context=None):
+                               entries = Blog.entries.all()
+                               # filter entries based on the year, month, and day.
+                               return entries, extra_context
+               
+               .. seealso:: :meth:`get_feed_type`
                
                """
                urlpatterns = patterns('')
@@ -143,7 +164,11 @@ class FeedView(MultiView):
        
        def get_feed_type(self, request, feed_type=None):
                """
-               If ``feed_type`` is not ``None``, returns the corresponding class from the registry or reises :exc:`.HttpNotAcceptable`. Otherwise, intelligently chooses a feed type for a given request. Tries to return :attr:`feed_type`, but if the Accept header does not include that mimetype, tries to return the best match from the feed types that are offered by the :class:`FeedView`. If none of the offered feed types are accepted by the :class:`HttpRequest`, raises :exc:`.HttpNotAcceptable`.
+               If ``feed_type`` is not ``None``, returns the corresponding class from the registry or raises :exc:`.HttpNotAcceptable`.
+               
+               Otherwise, intelligently chooses a feed type for a given request. Tries to return :attr:`feed_type`, but if the Accept header does not include that mimetype, tries to return the best match from the feed types that are offered by the :class:`FeedView`. If none of the offered feed types are accepted by the :class:`HttpRequest`, raises :exc:`.HttpNotAcceptable`.
+               
+               If `mimeparse <http://code.google.com/p/mimeparse/>`_ is installed, it will be used to select the best matching accepted format; otherwise, the first available format that is accepted will be selected.
                
                """
                if feed_type is not None: