From 17d46134395cc0584ed6ba54b69e47490dc5b6a9 Mon Sep 17 00:00:00 2001 From: Stephen Burrows Date: Wed, 19 Jan 2011 13:36:21 -0500 Subject: [PATCH] Improved blog and newsletter ModelAdmins. Set BlogEntries and NewsletterArticlesup to set their dates on save if it wasn't set manually - gives more accurate publishing times than a datetime.now() default. Set feed creation to use templates for title and description so that projects can customize the display for markdown etc. Limited Attribute.key to word characters to ensure template usability. Ordered Tags by name. --- contrib/penfield/admin.py | 91 +++++++++++++++++-- contrib/penfield/models.py | 39 +++++--- .../feeds/blog_entry/description.html | 1 + .../penfield/feeds/blog_entry/title.html | 1 + .../feeds/newsletter_article/description.html | 1 + .../feeds/newsletter_article/title.html | 1 + models/base.py | 4 +- 7 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 contrib/penfield/templates/penfield/feeds/blog_entry/description.html create mode 100644 contrib/penfield/templates/penfield/feeds/blog_entry/title.html create mode 100644 contrib/penfield/templates/penfield/feeds/newsletter_article/description.html create mode 100644 contrib/penfield/templates/penfield/feeds/newsletter_article/title.html diff --git a/contrib/penfield/admin.py b/contrib/penfield/admin.py index c758e67..d8fcd90 100644 --- a/contrib/penfield/admin.py +++ b/contrib/penfield/admin.py @@ -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) diff --git a/contrib/penfield/models.py b/contrib/penfield/models.py index 9f1b61b..b19d3a1 100644 --- a/contrib/penfield/models.py +++ b/contrib/penfield/models.py @@ -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 index 0000000..61060d5 --- /dev/null +++ b/contrib/penfield/templates/penfield/feeds/blog_entry/description.html @@ -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 index 0000000..f7167dd --- /dev/null +++ b/contrib/penfield/templates/penfield/feeds/blog_entry/title.html @@ -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 index 0000000..78e19ce --- /dev/null +++ b/contrib/penfield/templates/penfield/feeds/newsletter_article/description.html @@ -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 index 0000000..1f96b1f --- /dev/null +++ b/contrib/penfield/templates/penfield/feeds/newsletter_article/title.html @@ -0,0 +1 @@ +{{ article.title }} \ No newline at end of file diff --git a/models/base.py b/models/base.py index fae385a..8140520 100644 --- a/models/base.py +++ b/models/base.py @@ -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) -- 2.20.1