Merge branch 'node_url_refactor'
authorStephen Burrows <stephen.r.burrows@gmail.com>
Thu, 21 Oct 2010 19:57:01 +0000 (15:57 -0400)
committerStephen Burrows <stephen.r.burrows@gmail.com>
Thu, 21 Oct 2010 19:57:01 +0000 (15:57 -0400)
1  2 
contrib/penfield/models.py
models/nodes.py

@@@ -3,9 -3,8 +3,8 @@@ from django.conf import setting
  from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model, TemplateField
  from philo.exceptions import ViewCanNotProvideSubpath
  from django.conf.urls.defaults import url, patterns, include
- from django.core.urlresolvers import reverse
  from django.http import Http404
- from datetime import datetime
+ from datetime import date, datetime
  from philo.utils import paginate
  from philo.contrib.penfield.validators import validate_pagination_count
  from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
@@@ -75,7 -74,7 +74,7 @@@ class BlogView(MultiView, FeedMultiView
        def per_page(self):
                return self.entries_per_page
        
-       def get_subpath(self, obj):
+       def get_reverse_params(self, obj):
                if isinstance(obj, BlogEntry):
                        if obj.blog == self.blog:
                                kwargs = {'slug': obj.slug}
                                                kwargs.update({'month': str(obj.date.month).zfill(2)})
                                                if self.entry_permalink_style == 'D':
                                                        kwargs.update({'day': str(obj.date.day).zfill(2)})
-                               return reverse(self.entry_view, urlconf=self, kwargs=kwargs)
+                               return self.entry_view, [], kwargs
                elif isinstance(obj, Tag):
                        if obj in self.blog.entry_tags:
-                               return reverse('entries_by_tag', urlconf=self, kwargs={'tag_slugs': obj.slug})
-               elif isinstance(obj, (str, unicode)):
-                       split_obj = obj.split(':')
-                       if len(split_obj) > 1:
-                               kwargs = {}
-                               try:
-                                       kwargs.update({'year': str(int(split_obj[1])).zfill(4)})
-                                       if len(split_obj) > 2:
-                                               kwargs.update({'month': str(int(split_obj[2])).zfill(2)})
-                                               if len(split_obj) > 3:
-                                                       kwargs.update({'day': str(int(split_obj[3])).zfill(2)})
-                                                       return reverse('entries_by_day', urlconf=self, kwargs=kwargs)
-                                               return reverse('entries_by_month', urlconf=self, kwargs=kwargs)
-                                       return reverse('entries_by_year', urlconf=self, kwargs=kwargs)
-                               except:
-                                       pass
+                               return 'entries_by_tag', [], {'tag_slugs': obj.slug}
+               elif isinstance(obj, (date, datetime)):
+                       kwargs = {
+                               'year': str(obj.year).zfill(4),
+                               'month': str(obj.month).zfill(2),
+                               'day': str(obj.day).zfill(2)
+                       }
+                       return 'entries_by_day', [], kwargs
                raise ViewCanNotProvideSubpath
        
        def get_context(self):
                        )
                return urlpatterns
        
 -      def get_all_entries(self, request, node=None, extra_context=None):
 +      def get_all_entries(self, request, extra_context=None):
                return self.blog.entries.all(), extra_context
        
 -      def get_entries_by_ymd(self, request, year=None, month=None, day=None, node=None, extra_context=None):
 +      def get_entries_by_ymd(self, request, year=None, month=None, day=None, extra_context=None):
                if not self.entry_archive_page:
                        raise Http404
                entries = self.blog.entries.all()
                context.update({'year': year, 'month': month, 'day': day})
                return entries, context
        
 -      def get_entries_by_tag(self, request, tag_slugs, node=None, extra_context=None):
 +      def get_entries_by_tag(self, request, tag_slugs, extra_context=None):
                tags = []
                for tag_slug in tag_slugs.replace('+', '/').split('/'):
                        if tag_slug: # ignore blank slugs, handles for multiple consecutive separators (+ or /)
                defaults.update(kwargs or {})
                return super(BlogView, self).get_feed(feed_type, extra_context, defaults)
        
 -      def entry_view(self, request, slug, year=None, month=None, day=None, node=None, extra_context=None):
 +      def entry_view(self, request, slug, year=None, month=None, day=None, extra_context=None):
                entries = self.blog.entries.all()
                if year:
                        entries = entries.filter(date__year=year)
                context = self.get_context()
                context.update(extra_context or {})
                context.update({'entry': entry})
 -              return self.entry_page.render_to_response(node, request, extra_context=context)
 +              return self.entry_page.render_to_response(request, extra_context=context)
        
 -      def tag_archive_view(self, request, node=None, extra_context=None):
 +      def tag_archive_view(self, request, extra_context=None):
                if not self.tag_archive_page:
                        raise Http404
                context = {}
                context.update(extra_context or {})
                context.update({'blog': self.blog})
 -              return self.tag_archive_page.render_to_response(node, request, extra_context=context)
 +              return self.tag_archive_page.render_to_response(request, extra_context=context)
  
  
  class Newsletter(Entity, Titled):
@@@ -258,7 -249,7 +249,7 @@@ class NewsletterArticle(Entity, Titled)
        authors = models.ManyToManyField(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'), related_name='newsletterarticles')
        date = models.DateTimeField(default=datetime.now)
        lede = TemplateField(null=True, blank=True, verbose_name='Summary')
 -      full_text = TemplateField()
 +      full_text = TemplateField(db_index=True)
        tags = models.ManyToManyField(Tag, related_name='newsletterarticles', blank=True, null=True)
        
        class Meta:
@@@ -310,7 -301,7 +301,7 @@@ class NewsletterView(MultiView, FeedMul
        def __unicode__(self):
                return self.newsletter.__unicode__()
        
-       def get_subpath(self, obj):
+       def get_reverse_params(self, obj):
                if isinstance(obj, NewsletterArticle):
                        if obj.newsletter == self.newsletter:
                                kwargs = {'slug': obj.slug}
                                                kwargs.update({'month': str(obj.date.month).zfill(2)})
                                                if self.article_permalink_style == 'D':
                                                        kwargs.update({'day': str(obj.date.day).zfill(2)})
-                               return reverse(self.article_view, urlconf=self, kwargs=kwargs)
+                               return self.article_view, [], kwargs
                elif isinstance(obj, NewsletterIssue):
                        if obj.newsletter == self.newsletter:
-                               return reverse('issue', urlconf=self, kwargs={'numbering': obj.numbering})
+                               return 'issue', [], {'numbering': obj.numbering}
+               elif isinstance(obj, (date, datetime)):
+                       kwargs = {
+                               'year': str(obj.year).zfill(4),
+                               'month': str(obj.month).zfill(2),
+                               'day': str(obj.day).zfill(2)
+                       }
+                       return 'articles_by_day', [], kwargs
                raise ViewCanNotProvideSubpath
        
        @property
        def get_context(self):
                return {'newsletter': self.newsletter}
        
 -      def get_all_articles(self, request, node, extra_context=None):
 +      def get_all_articles(self, request, extra_context=None):
                return self.newsletter.articles.all(), extra_context
        
 -      def get_articles_by_ymd(self, request, year, month=None, day=None, node=None, extra_context=None):
 +      def get_articles_by_ymd(self, request, year, month=None, day=None, extra_context=None):
                articles = self.newsletter.articles.filter(dat__year=year)
                if month:
                        articles = articles.filter(date__month=month)
                        articles = articles.filter(date__day=day)
                return articles
        
 -      def get_articles_by_issue(self, request, numbering, node=None, extra_context=None):
 +      def get_articles_by_issue(self, request, numbering, extra_context=None):
                try:
                        issue = self.newsletter.issues.get(numbering=numbering)
                except:
                context.update({'issue': issue})
                return issue.articles.all(), context
        
 -      def article_view(self, request, slug, year=None, month=None, day=None, node=None, extra_context=None):
 +      def article_view(self, request, slug, year=None, month=None, day=None, extra_context=None):
                articles = self.newsletter.articles.all()
                if year:
                        articles = articles.filter(date__year=year)
                context = self.get_context()
                context.update(extra_context or {})
                context.update({'article': article})
 -              return self.article_page.render_to_response(node, request, extra_context=context)
 +              return self.article_page.render_to_response(request, extra_context=context)
        
 -      def issue_archive_view(self, request, node=None, extra_context=None):
 +      def issue_archive_view(self, request, extra_context=None):
                if not self.issue_archive_page:
                        raise Http404
                context = {}
                context.update(extra_context or {})
                context.update({'newsletter': self.newsletter})
 -              return self.issue_archive_page.render_to_response(node, request, extra_context=context)
 +              return self.issue_archive_page.render_to_response(request, extra_context=context)
        
        def add_item(self, feed, obj, kwargs=None):
                defaults = {
diff --combined models/nodes.py
@@@ -3,11 -3,11 +3,12 @@@ from django.contrib.contenttypes.model
  from django.contrib.contenttypes import generic
  from django.contrib.sites.models import Site
  from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
+ from django.core.exceptions import ViewDoesNotExist
  from django.core.servers.basehttp import FileWrapper
- from django.core.urlresolvers import resolve, clear_url_caches
+ from django.core.urlresolvers import resolve, clear_url_caches, reverse
  from django.template import add_to_builtins as register_templatetags
  from inspect import getargspec
 +from philo.exceptions import MIDDLEWARE_NOT_CONFIGURED
  from philo.models.base import TreeEntity, Entity, QuerySetMapper, register_value_model
  from philo.utils import ContentTypeSubclassLimiter
  from philo.validators import RedirectValidator
@@@ -29,14 -29,22 +30,22 @@@ class Node(TreeEntity)
                        return self.view.accepts_subpath
                return False
        
 -      def render_to_response(self, request, path=None, subpath=None, extra_context=None):
 -              return self.view.render_to_response(self, request, path, subpath, extra_context)
 +      def render_to_response(self, request, extra_context=None):
 +              return self.view.render_to_response(request, extra_context)
        
        def get_absolute_url(self):
-               root = Site.objects.get_current().root_node
                try:
-                       return '/%s' % self.get_path(root=root)
-               except AncestorDoesNotExist:
+                       root = Site.objects.get_current().root_node
+               except Site.DoesNotExist:
+                       root = None
+               
+               try:
+                       path = self.get_path(root=root)
+                       if path:
+                               path += '/'
+                       root_url = reverse('philo-root')
+                       return '%s%s' % (root_url, path)
+               except AncestorDoesNotExist, ViewDoesNotExist:
                        return None
        
        class Meta:
@@@ -58,17 -66,17 +67,17 @@@ class View(Entity)
        def attributes_with_node(self, node):
                return QuerySetMapper(self.attribute_set, passthrough=node.attributes)
        
 -      def relationships_with_node(self, node):
 -              return QuerySetMapper(self.relationship_set, passthrough=node.relationships)
 -      
 -      def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
 +      def render_to_response(self, request, extra_context=None):
 +              if not hasattr(request, 'node'):
 +                      raise MIDDLEWARE_NOT_CONFIGURED
 +              
                extra_context = extra_context or {}
 -              view_about_to_render.send(sender=self, node=node, request=request, path=path, subpath=subpath, extra_context=extra_context)
 -              response = self.actually_render_to_response(node, request, path, subpath, extra_context)
 +              view_about_to_render.send(sender=self, request=request, extra_context=extra_context)
 +              response = self.actually_render_to_response(request, extra_context)
                view_finished_rendering.send(sender=self, response=response)
                return response
        
 -      def actually_render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
 +      def actually_render_to_response(self, request, extra_context=None):
                raise NotImplementedError('View subclasses must implement render_to_response.')
        
        class Meta:
@@@ -81,11 -89,16 +90,17 @@@ _view_content_type_limiter.cls = Vie
  class MultiView(View):
        accepts_subpath = True
        
-       urlpatterns = []
+       @property
+       def urlpatterns(self, obj):
+               raise NotImplementedError("MultiView subclasses must implement urlpatterns.")
+       
+       def get_reverse_params(self, obj):
+               """This method should return a view_name, args, kwargs tuple suitable for reversing a url for the given obj using self as the urlconf."""
+               raise NotImplementedError("MultiView subclasses must implement get_subpath.")
        
 -      def actually_render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
 +      def actually_render_to_response(self, request, extra_context=None):
                clear_url_caches()
 +              subpath = request.node.subpath
                if not subpath:
                        subpath = ""
                subpath = "/" + subpath
                        if 'extra_context' in kwargs:
                                extra_context.update(kwargs['extra_context'])
                        kwargs['extra_context'] = extra_context
 -              if 'node' in view_args[0] or view_args[2] is not None:
 -                      kwargs['node'] = node
                return view(request, *args, **kwargs)
        
        class Meta:
@@@ -109,7 -124,7 +124,7 @@@ class Redirect(View)
        target = models.CharField(max_length=200, validators=[RedirectValidator()])
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
 -      def actually_render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
 +      def actually_render_to_response(self, request, extra_context=None):
                response = HttpResponseRedirect(self.target)
                response.status_code = self.status_code
                return response
                app_label = 'philo'
  
  
 +# Why does this exist?
  class File(View):
        """ For storing arbitrary files """
        
        mimetype = models.CharField(max_length=255)
        file = models.FileField(upload_to='philo/files/%Y/%m/%d')
        
 -      def actually_render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
 +      def actually_render_to_response(self, request, extra_context=None):
                wrapper = FileWrapper(self.file)
                response = HttpResponse(wrapper, content_type=self.mimetype)
                response['Content-Length'] = self.file.size