Improved blog and newsletter ModelAdmins. Set BlogEntries and NewsletterArticlesup...
authorStephen Burrows <stephen.r.burrows@gmail.com>
Wed, 19 Jan 2011 18:36:21 +0000 (13:36 -0500)
committerStephen Burrows <stephen.r.burrows@gmail.com>
Wed, 19 Jan 2011 19:06:27 +0000 (14:06 -0500)
contrib/penfield/admin.py
contrib/penfield/models.py
contrib/penfield/templates/penfield/feeds/blog_entry/description.html [new file with mode: 0644]
contrib/penfield/templates/penfield/feeds/blog_entry/title.html [new file with mode: 0644]
contrib/penfield/templates/penfield/feeds/newsletter_article/description.html [new file with mode: 0644]
contrib/penfield/templates/penfield/feeds/newsletter_article/title.html [new file with mode: 0644]
models/base.py

index c758e67..d8fcd90 100644 (file)
@@ -1,8 +1,17 @@
 from django.contrib import admin
-from philo.admin import EntityAdmin, AddTagAdmin
+from django import forms
+from philo.admin import EntityAdmin, AddTagAdmin, COLLAPSE_CLASSES
 from philo.contrib.penfield.models import BlogEntry, Blog, BlogView, Newsletter, NewsletterArticle, NewsletterIssue, NewsletterView
 
 
+class DelayedDateForm(forms.ModelForm):
+       date_field = 'date'
+       
+       def __init__(self, *args, **kwargs):
+               super(DelayedDateForm, self).__init__(*args, **kwargs)
+               self.fields[self.date_field].required = False
+
+
 class TitledAdmin(EntityAdmin):
        prepopulated_fields = {'slug': ('title',)}
        list_display = ('title', 'slug')
@@ -13,11 +22,48 @@ class BlogAdmin(TitledAdmin):
 
 
 class BlogEntryAdmin(TitledAdmin, AddTagAdmin):
+       form = DelayedDateForm
        filter_horizontal = ['tags']
+       list_filter = ['author', 'blog']
+       date_hierarchy = 'date'
+       search_fields = ('content',)
+       list_display = ['title', 'date', 'author']
+       raw_id_fields = ('author',)
+       fieldsets = (
+               (None, {
+                       'fields': ('title', 'author', 'blog')
+               }),
+               ('Content', {
+                       'fields': ('content', 'excerpt', 'tags'),
+               }),
+               ('Advanced', {
+                       'fields': ('slug', 'date'),
+                       'classes': COLLAPSE_CLASSES
+               })
+       )
 
 
 class BlogViewAdmin(EntityAdmin):
-       pass
+       fieldsets = (
+               (None, {
+                       'fields': ('blog',)
+               }),
+               ('Pages', {
+                       'fields': ('index_page', 'entry_page', 'tag_page')
+               }),
+               ('Archive Pages', {
+                       'fields': ('entry_archive_page', 'tag_archive_page')
+               }),
+               ('Permalinks', {
+                       'fields': ('entry_permalink_style', 'entry_permalink_base', 'tag_permalink_base'),
+                       'classes': COLLAPSE_CLASSES
+               }),
+               ('Feeds', {
+                       'fields': ('feed_suffix', 'feeds_enabled'),
+                       'classes': COLLAPSE_CLASSES
+               })
+       )
+       raw_id_fields = ('index_page', 'entry_page', 'tag_page', 'entry_archive_page', 'tag_archive_page',)
 
 
 class NewsletterAdmin(TitledAdmin):
@@ -25,10 +71,24 @@ class NewsletterAdmin(TitledAdmin):
 
 
 class NewsletterArticleAdmin(TitledAdmin, AddTagAdmin):
-       filter_horizontal = TitledAdmin.filter_horizontal + ('tags', 'authors')
-       list_display = ['title', 'date', 'author_names']
-       search_fields = ('title', 'authors__name',)
+       form = DelayedDateForm
+       filter_horizontal = ('tags', 'authors')
+       list_filter = ('newsletter',)
        date_hierarchy = 'date'
+       search_fields = ('title', 'authors__name',)
+       list_display = ['title', 'date', 'author_names']
+       fieldsets = (
+               (None, {
+                       'fields': ('title', 'authors', 'newsletter')
+               }),
+               ('Content', {
+                       'fields': ('full_text', 'lede', 'tags')
+               }),
+               ('Advanced', {
+                       'fields': ('slug', 'date'),
+                       'classes': COLLAPSE_CLASSES
+               })
+       )
        
        def author_names(self, obj):
                return ', '.join([author.get_full_name() for author in obj.authors.all()])
@@ -40,7 +100,26 @@ class NewsletterIssueAdmin(TitledAdmin):
 
 
 class NewsletterViewAdmin(EntityAdmin):
-       pass
+       fieldsets = (
+               (None, {
+                       'fields': ('newsletter',)
+               }),
+               ('Pages', {
+                       'fields': ('index_page', 'article_page', 'issue_page')
+               }),
+               ('Archive Pages', {
+                       'fields': ('article_archive_page', 'issue_archive_page')
+               }),
+               ('Permalinks', {
+                       'fields': ('article_permalink_style', 'article_permalink_base', 'issue_permalink_base'),
+                       'classes': COLLAPSE_CLASSES
+               }),
+               ('Feeds', {
+                       'fields': ('feed_suffix', 'feeds_enabled'),
+                       'classes': COLLAPSE_CLASSES
+               })
+       )
+       raw_id_fields = ('index_page', 'article_page', 'issue_page', 'article_archive_page', 'issue_archive_page',)
 
 
 admin.site.register(Blog, BlogAdmin)
index 9f1b61b..b19d3a1 100644 (file)
@@ -1,14 +1,15 @@
-from django.db import models
 from django.conf import settings
-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.db import models
 from django.http import Http404
-from datetime import date, datetime
-from philo.utils import paginate
-from philo.contrib.penfield.validators import validate_pagination_count
+from django.template import loader, Context
 from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
+from datetime import date, datetime
 from philo.contrib.penfield.utils import FeedMultiViewMixin
+from philo.contrib.penfield.validators import validate_pagination_count
+from philo.exceptions import ViewCanNotProvideSubpath
+from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model, TemplateField
+from philo.utils import paginate
 
 
 class Blog(Entity, Titled):
@@ -29,11 +30,16 @@ register_value_model(Blog)
 class BlogEntry(Entity, Titled):
        blog = models.ForeignKey(Blog, related_name='entries', blank=True, null=True)
        author = models.ForeignKey(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'), related_name='blogentries')
-       date = models.DateTimeField(default=datetime.now)
+       date = models.DateTimeField(default=None)
        content = models.TextField()
        excerpt = models.TextField(blank=True, null=True)
        tags = models.ManyToManyField(Tag, related_name='blogentries', blank=True, null=True)
        
+       def save(self, *args, **kwargs):
+               if self.date is None:
+                       self.date = datetime.now()
+               super(BlogEntry, self).save(*args, **kwargs)
+       
        class Meta:
                ordering = ['-date']
                verbose_name_plural = "blog entries"
@@ -195,9 +201,11 @@ class BlogView(MultiView, FeedMultiViewMixin):
                return entries, context
        
        def add_item(self, feed, obj, kwargs=None):
+               title = loader.get_template("penfield/feeds/blog_entry/title.html")
+               description = loader.get_template("penfield/feeds/blog_entry/description.html")
                defaults = {
-                       'title': obj.title,
-                       'description': obj.content,
+                       'title': title.render(Context({'entry': obj})),
+                       'description': description.render(Context({'entry': obj})),
                        'author_name': obj.author.get_full_name(),
                        'pubdate': obj.date
                }
@@ -253,11 +261,16 @@ register_value_model(Newsletter)
 class NewsletterArticle(Entity, Titled):
        newsletter = models.ForeignKey(Newsletter, related_name='articles')
        authors = models.ManyToManyField(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'), related_name='newsletterarticles')
-       date = models.DateTimeField(default=datetime.now)
+       date = models.DateTimeField(default=None)
        lede = TemplateField(null=True, blank=True, verbose_name='Summary')
        full_text = TemplateField(db_index=True)
        tags = models.ManyToManyField(Tag, related_name='newsletterarticles', blank=True, null=True)
        
+       def save(self, *args, **kwargs):
+               if self.date is None:
+                       self.date = datetime.now()
+               super(NewsletterArticle, self).save(*args, **kwargs)
+       
        class Meta:
                get_latest_by = 'date'
                ordering = ['-date']
@@ -425,11 +438,13 @@ class NewsletterView(MultiView, FeedMultiViewMixin):
                return self.issue_archive_page.render_to_response(request, extra_context=context)
        
        def add_item(self, feed, obj, kwargs=None):
+               title = loader.get_template("penfield/feeds/newsletter_article/title.html")
+               description = loader.get_template("penfield/feeds/newsletter_article/description.html")
                defaults = {
-                       'title': obj.title,
+                       'title': title.render(Context({'article': obj})),
                        'author_name': ', '.join([author.get_full_name() for author in obj.authors.all()]),
                        'pubdate': obj.date,
-                       'description': obj.full_text,
+                       'description': description.render(Context({'article': obj})),
                        'categories': [tag.name for tag in obj.tags.all()]
                }
                defaults.update(kwargs or {})
diff --git a/contrib/penfield/templates/penfield/feeds/blog_entry/description.html b/contrib/penfield/templates/penfield/feeds/blog_entry/description.html
new file mode 100644 (file)
index 0000000..61060d5
--- /dev/null
@@ -0,0 +1 @@
+{{ entry.content }}
\ No newline at end of file
diff --git a/contrib/penfield/templates/penfield/feeds/blog_entry/title.html b/contrib/penfield/templates/penfield/feeds/blog_entry/title.html
new file mode 100644 (file)
index 0000000..f7167dd
--- /dev/null
@@ -0,0 +1 @@
+{{ entry.title }}
\ No newline at end of file
diff --git a/contrib/penfield/templates/penfield/feeds/newsletter_article/description.html b/contrib/penfield/templates/penfield/feeds/newsletter_article/description.html
new file mode 100644 (file)
index 0000000..78e19ce
--- /dev/null
@@ -0,0 +1 @@
+{{ article.full_text }}
\ No newline at end of file
diff --git a/contrib/penfield/templates/penfield/feeds/newsletter_article/title.html b/contrib/penfield/templates/penfield/feeds/newsletter_article/title.html
new file mode 100644 (file)
index 0000000..1f96b1f
--- /dev/null
@@ -0,0 +1 @@
+{{ article.title }}
\ No newline at end of file
index fae385a..8140520 100644 (file)
@@ -3,6 +3,7 @@ from django.db import models
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 from django.core.exceptions import ObjectDoesNotExist
+from django.core.validators import RegexValidator
 from django.utils import simplejson as json
 from django.utils.encoding import smart_str
 from philo.exceptions import AncestorDoesNotExist
@@ -23,6 +24,7 @@ class Tag(models.Model):
        
        class Meta:
                app_label = 'philo'
+               ordering = ('name',)
 
 
 class Titled(models.Model):
@@ -179,7 +181,7 @@ class Attribute(models.Model):
        value_object_id = models.PositiveIntegerField(verbose_name='Value ID', null=True, blank=True)
        value = generic.GenericForeignKey('value_content_type', 'value_object_id')
        
-       key = models.CharField(max_length=255)
+       key = models.CharField(max_length=255, validators=[RegexValidator("\w+")], help_text="Must contain one or more alphanumeric characters or underscores.")
        
        def __unicode__(self):
                return u'"%s": %s' % (self.key, self.value)