Corrections to Blog.entry_tags to use taggit APIs. Tweaks to penfield migration 0005...
[philo.git] / philo / contrib / penfield / models.py
index e31de9f..eef8974 100644 (file)
@@ -4,10 +4,12 @@ from django.conf import settings
 from django.conf.urls.defaults import url, patterns, include
 from django.db import models
 from django.http import Http404, HttpResponse
 from django.conf.urls.defaults import url, patterns, include
 from django.db import models
 from django.http import Http404, HttpResponse
+from taggit.managers import TaggableManager
+from taggit.models import Tag, TaggedItem
 
 
-from philo.contrib.syndication.models import FeedView
+from philo.contrib.winer.models import FeedView
 from philo.exceptions import ViewCanNotProvideSubpath
 from philo.exceptions import ViewCanNotProvideSubpath
-from philo.models import Tag, Entity, Page, register_value_model
+from philo.models import Entity, Page, register_value_model
 from philo.models.fields import TemplateField
 from philo.utils import paginate
 
 from philo.models.fields import TemplateField
 from philo.utils import paginate
 
@@ -26,7 +28,11 @@ class Blog(Entity):
        @property
        def entry_tags(self):
                """Returns a :class:`QuerySet` of :class:`.Tag`\ s that are used on any entries in this blog."""
        @property
        def entry_tags(self):
                """Returns a :class:`QuerySet` of :class:`.Tag`\ s that are used on any entries in this blog."""
-               return Tag.objects.filter(blogentries__blog=self).distinct()
+               entry_pks = list(self.entries.values_list('pk', flat=True))
+               kwargs = {
+                       '%s__object_id__in' % TaggedItem.tag_relname(): entry_pks
+               }
+               return TaggedItem.tags_for(BlogEntry).filter(**kwargs)
        
        @property
        def entry_dates(self):
        
        @property
        def entry_dates(self):
@@ -61,8 +67,8 @@ class BlogEntry(Entity):
        #: An optional brief excerpt from the :class:`BlogEntry`.
        excerpt = models.TextField(blank=True, null=True)
        
        #: An optional brief excerpt from the :class:`BlogEntry`.
        excerpt = models.TextField(blank=True, null=True)
        
-       #: :class:`.Tag`\ s for this :class:`BlogEntry`.
-       tags = models.ManyToManyField(Tag, related_name='blogentries', blank=True, null=True)
+       #: A ``django-taggit`` :class:`TaggableManager`.
+       tags = TaggableManager()
        
        def save(self, *args, **kwargs):
                if self.date is None:
        
        def save(self, *args, **kwargs):
                if self.date is None:
@@ -83,7 +89,7 @@ register_value_model(BlogEntry)
 
 class BlogView(FeedView):
        """
 
 class BlogView(FeedView):
        """
-       A subclass of :class:`FeedView` which handles patterns and feeds for a :class:`Blog` and its related :class:`entries <BlogEntry>`.
+       A subclass of :class:`.FeedView` which handles patterns and feeds for a :class:`Blog` and its related :class:`entries <BlogEntry>`.
        
        """
        ENTRY_PERMALINK_STYLE_CHOICES = (
        
        """
        ENTRY_PERMALINK_STYLE_CHOICES = (
@@ -132,7 +138,7 @@ class BlogView(FeedView):
        
        def get_reverse_params(self, obj):
                if isinstance(obj, BlogEntry):
        
        def get_reverse_params(self, obj):
                if isinstance(obj, BlogEntry):
-                       if obj.blog == self.blog:
+                       if obj.blog_id == self.blog_id:
                                kwargs = {'slug': obj.slug}
                                if self.entry_permalink_style in 'DMY':
                                        kwargs.update({'year': str(obj.date.year).zfill(4)})
                                kwargs = {'slug': obj.slug}
                                if self.entry_permalink_style in 'DMY':
                                        kwargs.update({'year': str(obj.date.year).zfill(4)})
@@ -144,7 +150,7 @@ class BlogView(FeedView):
                elif isinstance(obj, Tag) or (isinstance(obj, models.query.QuerySet) and obj.model == Tag and obj):
                        if isinstance(obj, Tag):
                                obj = [obj]
                elif isinstance(obj, Tag) or (isinstance(obj, models.query.QuerySet) and obj.model == Tag and obj):
                        if isinstance(obj, Tag):
                                obj = [obj]
-                       slugs = [tag.slug for tag in obj if tag in self.get_tag_queryset()]
+                       slugs = [tag.slug for tag in obj if tag in self.get_tag_queryset(self.blog)]
                        if slugs:
                                return 'entries_by_tag', [], {'tag_slugs': "/".join(slugs)}
                elif isinstance(obj, (date, datetime)):
                        if slugs:
                                return 'entries_by_tag', [], {'tag_slugs': "/".join(slugs)}
                elif isinstance(obj, (date, datetime)):
@@ -159,14 +165,14 @@ class BlogView(FeedView):
        @property
        def urlpatterns(self):
                urlpatterns = self.feed_patterns(r'^', 'get_all_entries', 'index_page', 'index') +\
        @property
        def urlpatterns(self):
                urlpatterns = self.feed_patterns(r'^', 'get_all_entries', 'index_page', 'index') +\
-                       self.feed_patterns(r'^%s/(?P<tag_slugs>[-\w]+[-+/\w]*)$' % self.tag_permalink_base, 'get_entries_by_tag', 'tag_page', 'entries_by_tag')
+                       self.feed_patterns(r'^%s/(?P<tag_slugs>[-\w]+[-+/\w]*)' % self.tag_permalink_base, 'get_entries_by_tag', 'tag_page', 'entries_by_tag')
                
                
-               if self.tag_archive_page:
+               if self.tag_archive_page_id:
                        urlpatterns += patterns('',
                                url((r'^%s$' % self.tag_permalink_base), self.tag_archive_view, name='tag_archive')
                        )
                
                        urlpatterns += patterns('',
                                url((r'^%s$' % self.tag_permalink_base), self.tag_archive_view, name='tag_archive')
                        )
                
-               if self.entry_archive_page:
+               if self.entry_archive_page_id:
                        if self.entry_permalink_style in 'DMY':
                                urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_year')
                                if self.entry_permalink_style in 'DM':
                        if self.entry_permalink_style in 'DMY':
                                urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_year')
                                if self.entry_permalink_style in 'DM':
@@ -199,23 +205,23 @@ class BlogView(FeedView):
        def get_context(self):
                return {'blog': self.blog}
        
        def get_context(self):
                return {'blog': self.blog}
        
-       def get_entry_queryset(self):
-               """Returns the default :class:`QuerySet` of :class:`BlogEntry` instances for the :class:`BlogView`."""
-               return self.blog.entries.all()
+       def get_entry_queryset(self, obj):
+               """Returns the default :class:`QuerySet` of :class:`BlogEntry` instances for the :class:`BlogView` - all entries that are considered posted in the past. This allows for scheduled posting of entries."""
+               return obj.entries.filter(date__lte=datetime.now())
        
        
-       def get_tag_queryset(self):
+       def get_tag_queryset(self, obj):
                """Returns the default :class:`QuerySet` of :class:`.Tag`\ s for the :class:`BlogView`'s :meth:`get_entries_by_tag` and :meth:`tag_archive_view`."""
                """Returns the default :class:`QuerySet` of :class:`.Tag`\ s for the :class:`BlogView`'s :meth:`get_entries_by_tag` and :meth:`tag_archive_view`."""
-               return self.blog.entry_tags
+               return obj.entry_tags
        
        
-       def get_all_entries(self, request, extra_context=None):
-               """Used to generate :meth:`~FeedView.feed_patterns` for all entries."""
-               return self.get_entry_queryset(), extra_context
+       def get_all_entries(self, obj, request, extra_context=None):
+               """Used to generate :meth:`~.FeedView.feed_patterns` for all entries."""
+               return self.get_entry_queryset(obj), extra_context
        
        
-       def get_entries_by_ymd(self, request, year=None, month=None, day=None, extra_context=None):
-               """Used to generate :meth:`~FeedView.feed_patterns` for entries with a specific year, month, and day."""
+       def get_entries_by_ymd(self, obj, request, year=None, month=None, day=None, extra_context=None):
+               """Used to generate :meth:`~.FeedView.feed_patterns` for entries with a specific year, month, and day."""
                if not self.entry_archive_page:
                        raise Http404
                if not self.entry_archive_page:
                        raise Http404
-               entries = self.get_entry_queryset()
+               entries = self.get_entry_queryset(obj)
                if year:
                        entries = entries.filter(date__year=year)
                if month:
                if year:
                        entries = entries.filter(date__year=year)
                if month:
@@ -227,10 +233,10 @@ class BlogView(FeedView):
                context.update({'year': year, 'month': month, 'day': day})
                return entries, context
        
                context.update({'year': year, 'month': month, 'day': day})
                return entries, context
        
-       def get_entries_by_tag(self, request, tag_slugs, extra_context=None):
-               """Used to generate :meth:`~FeedView.feed_patterns` for entries with all of the given tags."""
+       def get_entries_by_tag(self, obj, request, tag_slugs, extra_context=None):
+               """Used to generate :meth:`~.FeedView.feed_patterns` for entries with all of the given tags."""
                tag_slugs = tag_slugs.replace('+', '/').split('/')
                tag_slugs = tag_slugs.replace('+', '/').split('/')
-               tags = self.get_tag_queryset().filter(slug__in=tag_slugs)
+               tags = self.get_tag_queryset(obj).filter(slug__in=tag_slugs)
                
                if not tags:
                        raise Http404
                
                if not tags:
                        raise Http404
@@ -241,7 +247,7 @@ class BlogView(FeedView):
                        if slug and slug not in found_slugs:
                                raise Http404
 
                        if slug and slug not in found_slugs:
                                raise Http404
 
-               entries = self.get_entry_queryset()
+               entries = self.get_entry_queryset(obj)
                for tag in tags:
                        entries = entries.filter(tags=tag)
                
                for tag in tags:
                        entries = entries.filter(tags=tag)
                
@@ -252,7 +258,7 @@ class BlogView(FeedView):
        
        def entry_view(self, request, slug, year=None, month=None, day=None, extra_context=None):
                """Renders :attr:`entry_page` with the entry specified by the given parameters."""
        
        def entry_view(self, request, slug, year=None, month=None, day=None, extra_context=None):
                """Renders :attr:`entry_page` with the entry specified by the given parameters."""
-               entries = self.get_entry_queryset()
+               entries = self.get_entry_queryset(self.blog)
                if year:
                        entries = entries.filter(date__year=year)
                if month:
                if year:
                        entries = entries.filter(date__year=year)
                if month:
@@ -275,17 +281,17 @@ class BlogView(FeedView):
                context = self.get_context()
                context.update(extra_context or {})
                context.update({
                context = self.get_context()
                context.update(extra_context or {})
                context.update({
-                       'tags': self.get_tag_queryset()
+                       'tags': self.get_tag_queryset(self.blog)
                })
                return self.tag_archive_page.render_to_response(request, extra_context=context)
        
                })
                return self.tag_archive_page.render_to_response(request, extra_context=context)
        
-       def feed_view(self, get_items_attr, reverse_name):
-               """Overrides :meth:`FeedView.feed_view` to add :class:`.Tag`\ s to the feed as categories."""
+       def feed_view(self, get_items_attr, reverse_name, feed_type=None):
+               """Overrides :meth:`.FeedView.feed_view` to add :class:`.Tag`\ s to the feed as categories."""
                get_items = callable(get_items_attr) and get_items_attr or getattr(self, get_items_attr)
                
                def inner(request, extra_context=None, *args, **kwargs):
                        obj = self.get_object(request, *args, **kwargs)
                get_items = callable(get_items_attr) and get_items_attr or getattr(self, get_items_attr)
                
                def inner(request, extra_context=None, *args, **kwargs):
                        obj = self.get_object(request, *args, **kwargs)
-                       feed = self.get_feed(obj, request, reverse_name)
+                       feed = self.get_feed(obj, request, reverse_name, feed_type, *args, **kwargs)
                        items, extra_context = get_items(request, extra_context=extra_context, *args, **kwargs)
                        self.populate_feed(feed, items, request)
                        
                        items, extra_context = get_items(request, extra_context=extra_context, *args, **kwargs)
                        self.populate_feed(feed, items, request)
                        
@@ -304,7 +310,7 @@ class BlogView(FeedView):
                return inner
        
        def process_page_items(self, request, items):
                return inner
        
        def process_page_items(self, request, items):
-               """Overrides :meth:`FeedView.process_page_items` to add pagination."""
+               """Overrides :meth:`.FeedView.process_page_items` to add pagination."""
                if self.entries_per_page:
                        page_num = request.GET.get('page', 1)
                        paginator, paginated_page, items = paginate(items, self.entries_per_page, page_num)
                if self.entries_per_page:
                        page_num = request.GET.get('page', 1)
                        paginator, paginated_page, items = paginate(items, self.entries_per_page, page_num)
@@ -368,8 +374,8 @@ class NewsletterArticle(Entity):
        lede = TemplateField(null=True, blank=True, verbose_name='Summary')
        #: A :class:`.TemplateField` containing the full text of the article.
        full_text = TemplateField(db_index=True)
        lede = TemplateField(null=True, blank=True, verbose_name='Summary')
        #: A :class:`.TemplateField` containing the full text of the article.
        full_text = TemplateField(db_index=True)
-       #: A :class:`ManyToManyField` to :class:`.Tag`\ s for the :class:`NewsletterArticle`.
-       tags = models.ManyToManyField(Tag, related_name='newsletterarticles', blank=True, null=True)
+       #: A ``django-taggit`` :class:`TaggableManager`.
+       tags = TaggableManager()
        
        def save(self, *args, **kwargs):
                if self.date is None:
        
        def save(self, *args, **kwargs):
                if self.date is None:
@@ -413,7 +419,7 @@ register_value_model(NewsletterIssue)
 
 
 class NewsletterView(FeedView):
 
 
 class NewsletterView(FeedView):
-       """A subclass of :class:`FeedView` which handles patterns and feeds for a :class:`Newsletter` and its related :class:`articles <NewsletterArticle>`."""
+       """A subclass of :class:`.FeedView` which handles patterns and feeds for a :class:`Newsletter` and its related :class:`articles <NewsletterArticle>`."""
        ARTICLE_PERMALINK_STYLE_CHOICES = (
                ('D', 'Year, month, and day'),
                ('M', 'Year and month'),
        ARTICLE_PERMALINK_STYLE_CHOICES = (
                ('D', 'Year, month, and day'),
                ('M', 'Year and month'),
@@ -455,7 +461,7 @@ class NewsletterView(FeedView):
        
        def get_reverse_params(self, obj):
                if isinstance(obj, NewsletterArticle):
        
        def get_reverse_params(self, obj):
                if isinstance(obj, NewsletterArticle):
-                       if obj.newsletter == self.newsletter:
+                       if obj.newsletter_id == self.newsletter_id:
                                kwargs = {'slug': obj.slug}
                                if self.article_permalink_style in 'DMY':
                                        kwargs.update({'year': str(obj.date.year).zfill(4)})
                                kwargs = {'slug': obj.slug}
                                if self.article_permalink_style in 'DMY':
                                        kwargs.update({'year': str(obj.date.year).zfill(4)})
@@ -465,7 +471,7 @@ class NewsletterView(FeedView):
                                                        kwargs.update({'day': str(obj.date.day).zfill(2)})
                                return self.article_view, [], kwargs
                elif isinstance(obj, NewsletterIssue):
                                                        kwargs.update({'day': str(obj.date.day).zfill(2)})
                                return self.article_view, [], kwargs
                elif isinstance(obj, NewsletterIssue):
-                       if obj.newsletter == self.newsletter:
+                       if obj.newsletter_id == self.newsletter_id:
                                return 'issue', [], {'numbering': obj.numbering}
                elif isinstance(obj, (date, datetime)):
                        kwargs = {
                                return 'issue', [], {'numbering': obj.numbering}
                elif isinstance(obj, (date, datetime)):
                        kwargs = {
@@ -481,14 +487,12 @@ class NewsletterView(FeedView):
                urlpatterns = self.feed_patterns(r'^', 'get_all_articles', 'index_page', 'index') + patterns('',
                        url(r'^%s/(?P<numbering>.+)$' % self.issue_permalink_base, self.page_view('get_articles_by_issue', 'issue_page'), name='issue')
                )
                urlpatterns = self.feed_patterns(r'^', 'get_all_articles', 'index_page', 'index') + patterns('',
                        url(r'^%s/(?P<numbering>.+)$' % self.issue_permalink_base, self.page_view('get_articles_by_issue', 'issue_page'), name='issue')
                )
-               if self.issue_archive_page:
+               if self.issue_archive_page_id:
                        urlpatterns += patterns('',
                                url(r'^%s$' % self.issue_permalink_base, self.issue_archive_view, 'issue_archive')
                        )
                        urlpatterns += patterns('',
                                url(r'^%s$' % self.issue_permalink_base, self.issue_archive_view, 'issue_archive')
                        )
-               if self.article_archive_page:
-                       urlpatterns += patterns('',
-                               url(r'^%s' % self.article_permalink_base, include(self.feed_patterns('get_all_articles', 'article_archive_page', 'articles')))
-                       )
+               if self.article_archive_page_id:
+                       urlpatterns += self.feed_patterns(r'^%s' % self.article_permalink_base, 'get_all_articles', 'article_archive_page', 'articles')
                        if self.article_permalink_style in 'DMY':
                                urlpatterns += self.feed_patterns(r'^%s/(?P<year>\d{4})' % self.article_permalink_base, 'get_articles_by_ymd', 'article_archive_page', 'articles_by_year')
                                if self.article_permalink_style in 'DM':
                        if self.article_permalink_style in 'DMY':
                                urlpatterns += self.feed_patterns(r'^%s/(?P<year>\d{4})' % self.article_permalink_base, 'get_articles_by_ymd', 'article_archive_page', 'articles_by_year')
                                if self.article_permalink_style in 'DM':
@@ -518,40 +522,40 @@ class NewsletterView(FeedView):
        def get_context(self):
                return {'newsletter': self.newsletter}
        
        def get_context(self):
                return {'newsletter': self.newsletter}
        
-       def get_article_queryset(self):
-               """Returns the default :class:`QuerySet` of :class:`NewsletterArticle` instances for the :class:`NewsletterView`."""
-               return self.newsletter.articles.all()
+       def get_article_queryset(self, obj):
+               """Returns the default :class:`QuerySet` of :class:`NewsletterArticle` instances for the :class:`NewsletterView` - all articles that are considered posted in the past. This allows for scheduled posting of articles."""
+               return obj.articles.filter(date__lte=datetime.now())
        
        
-       def get_issue_queryset(self):
+       def get_issue_queryset(self, obj):
                """Returns the default :class:`QuerySet` of :class:`NewsletterIssue` instances for the :class:`NewsletterView`."""
                """Returns the default :class:`QuerySet` of :class:`NewsletterIssue` instances for the :class:`NewsletterView`."""
-               return self.newsletter.issues.all()
+               return obj.issues.all()
        
        
-       def get_all_articles(self, request, extra_context=None):
-               """Used to generate :meth:`FeedView.feed_patterns` for all entries."""
-               return self.get_article_queryset(), extra_context
+       def get_all_articles(self, obj, request, extra_context=None):
+               """Used to generate :meth:`~.FeedView.feed_patterns` for all entries."""
+               return self.get_article_queryset(obj), extra_context
        
        
-       def get_articles_by_ymd(self, request, year, month=None, day=None, extra_context=None):
-               """Used to generate :meth:`FeedView.feed_patterns` for a specific year, month, and day."""
-               articles = self.get_article_queryset().filter(date__year=year)
+       def get_articles_by_ymd(self, obj, request, year, month=None, day=None, extra_context=None):
+               """Used to generate :meth:`~.FeedView.feed_patterns` for a specific year, month, and day."""
+               articles = self.get_article_queryset(obj).filter(date__year=year)
                if month:
                        articles = articles.filter(date__month=month)
                if day:
                        articles = articles.filter(date__day=day)
                return articles, extra_context
        
                if month:
                        articles = articles.filter(date__month=month)
                if day:
                        articles = articles.filter(date__day=day)
                return articles, extra_context
        
-       def get_articles_by_issue(self, request, numbering, extra_context=None):
-               """Used to generate :meth:`FeedView.feed_patterns` for articles from a certain issue."""
+       def get_articles_by_issue(self, obj, request, numbering, extra_context=None):
+               """Used to generate :meth:`~.FeedView.feed_patterns` for articles from a certain issue."""
                try:
                try:
-                       issue = self.get_issue_queryset().get(numbering=numbering)
+                       issue = self.get_issue_queryset(obj).get(numbering=numbering)
                except NewsletterIssue.DoesNotExist:
                        raise Http404
                context = extra_context or {}
                context.update({'issue': issue})
                except NewsletterIssue.DoesNotExist:
                        raise Http404
                context = extra_context or {}
                context.update({'issue': issue})
-               return self.get_article_queryset().filter(issues=issue), context
+               return self.get_article_queryset(obj).filter(issues=issue), context
        
        def article_view(self, request, slug, year=None, month=None, day=None, extra_context=None):
                """Renders :attr:`article_page` with the article specified by the given parameters."""
        
        def article_view(self, request, slug, year=None, month=None, day=None, extra_context=None):
                """Renders :attr:`article_page` with the article specified by the given parameters."""
-               articles = self.get_article_queryset()
+               articles = self.get_article_queryset(self.newsletter)
                if year:
                        articles = articles.filter(date__year=year)
                if month:
                if year:
                        articles = articles.filter(date__year=year)
                if month:
@@ -574,7 +578,7 @@ class NewsletterView(FeedView):
                context = self.get_context()
                context.update(extra_context or {})
                context.update({
                context = self.get_context()
                context.update(extra_context or {})
                context.update({
-                       'issues': self.get_issue_queryset()
+                       'issues': self.get_issue_queryset(self.newsletter)
                })
                return self.issue_archive_page.render_to_response(request, extra_context=context)
        
                })
                return self.issue_archive_page.render_to_response(request, extra_context=context)