Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
194 lines (151 sloc) 6.73 KB
"""
Models for a weblog application.
"""
import datetime
from comment_utils.managers import CommentedObjectManager
from comment_utils.moderation import CommentModerator, moderator
from django.conf import settings
from django.db import models
from django.utils.encoding import smart_str
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.comments import models as comment_models
import tagging
from tagging.fields import TagField
from template_utils.markup import formatter
from coltrane import managers
class Category(models.Model):
"""
A category that an Entry can belong to.
"""
title = models.CharField(max_length=250)
slug = models.SlugField(prepopulate_from=('title',), unique=True,
help_text=u'Used in the URL for the category. Must be unique.')
description = models.TextField(help_text=u'A short description of the category, to be used in list pages.')
description_html = models.TextField(editable=False, blank=True)
class Meta:
verbose_name_plural = 'Categories'
ordering = ['title']
class Admin:
pass
def __unicode__(self):
return self.title
def save(self):
self.description_html = formatter(self.description)
super(Category, self).save()
def get_absolute_url(self):
return ('coltrane_category_detail', (), { 'slug': self.slug })
get_absolute_url = models.permalink(get_absolute_url)
def _get_live_entries(self):
"""
Returns Entries in this Category with status of "live".
Access this through the property ``live_entry_set``.
"""
from coltrane.models import Entry
return self.entry_set.filter(status__exact=Entry.LIVE_STATUS)
live_entry_set = property(_get_live_entries)
class Entry(models.Model):
"""
An entry in the weblog.
Slightly denormalized, because it uses two fields each for the
excerpt and the body: one for the actual text the user types in,
and another to store the HTML version of the Entry (e.g., as
generated by a text-to-HTML converter like Textile or Markdown).
This saves having to run the conversion each time the Entry is
displayed.
Entries can be grouped by categories or by tags or both, or not
grouped at all.
"""
LIVE_STATUS = 1
DRAFT_STATUS = 2
HIDDEN_STATUS = 3
STATUS_CHOICES = (
(LIVE_STATUS, 'Live'),
(DRAFT_STATUS, 'Draft'),
(HIDDEN_STATUS, 'Hidden'),
)
# Metadata.
author = models.ForeignKey(User)
enable_comments = models.BooleanField(default=True)
featured = models.BooleanField(default=False)
pub_date = models.DateTimeField(u'Date posted', default=datetime.datetime.today)
slug = models.SlugField(prepopulate_from=('title',),
unique_for_date='pub_date',
help_text=u'Used in the URL of the entry. Must be unique for the publication date of the entry.')
status = models.IntegerField(choices=STATUS_CHOICES, default=LIVE_STATUS,
help_text=u'Only entries with "live" status will be displayed publicly.')
title = models.CharField(max_length=250)
# The actual entry bits.
body = models.TextField()
body_html = models.TextField(editable=False, blank=True)
excerpt = models.TextField(blank=True, null=True)
excerpt_html = models.TextField(blank=True, null=True, editable=False)
# Categorization.
categories = models.ManyToManyField(Category, filter_interface=models.HORIZONTAL, blank=True)
tags = TagField()
# Managers.
live = managers.LiveEntryManager()
objects = models.Manager()
class Meta:
get_latest_by = 'pub_date'
ordering = ['-pub_date']
verbose_name_plural = 'Entries'
class Admin:
date_hierarchy = 'pub_date'
fields = (
('Metadata', { 'fields':
('title', 'slug', 'pub_date', 'author', 'status', 'featured', 'enable_comments') }),
('Entry', { 'fields':
('excerpt', 'body') }),
('Categorization', { 'fields':
('tags', 'categories') }),
)
list_display = ('title', 'pub_date', 'author', 'status', 'enable_comments', '_get_comment_count')
list_filter = ('status', 'categories')
search_fields = ('excerpt', 'body', 'title')
def __unicode__(self):
return self.title
def save(self):
if self.excerpt:
self.excerpt_html = formatter(self.excerpt)
self.body_html = formatter(self.body)
super(Entry, self).save()
def get_absolute_url(self):
return ('coltrane_entry_detail', (), { 'year': self.pub_date.strftime('%Y'),
'month': self.pub_date.strftime('%b').lower(),
'day': self.pub_date.strftime('%d'),
'slug': self.slug })
get_absolute_url = models.permalink(get_absolute_url)
def _next_previous_helper(self, direction):
return getattr(self, 'get_%s_by_pub_date' % direction)(status__exact=self.LIVE_STATUS)
def get_next(self):
"""
Returns the next Entry with "live" status by ``pub_date``, if
there is one, or ``None`` if there isn't.
In public-facing templates, use this method instead of
``get_next_by_pub_date``, because ``get_next_by_pub_date``
does not differentiate entry status.
"""
return self._next_previous_helper('next')
def get_previous(self):
"""
Returns the previous Entry with "live" status by ``pub_date``,
if there is one, or ``None`` if there isn't.
In public-facing templates, use this method instead of
``get_previous_by_pub_date``, because
``get_previous_by_pub_date`` does not differentiate entry
status..
"""
return self._next_previous_helper('previous')
def _get_comment_count(self):
model = settings.USE_FREE_COMMENTS and comment_models.FreeComment or comment_models.Comment
ctype = ContentType.objects.get_for_model(self)
return model.objects.filter(content_type__pk=ctype.id, object_id__exact=self.id).count()
_get_comment_count.short_description = 'Number of comments'
class ColtraneModerator(CommentModerator):
akismet = True
auto_close_field = 'pub_date'
email_notification = True
enable_field = 'enable_comments'
close_after = settings.COMMENTS_MODERATE_AFTER
tagging.register(Entry, 'tag_set')