Added uniqueness constraints to Tag, NewsletterArticle, and NewsletterIssue, and...
[philo.git] / contrib / penfield / models.py
1 from django.db import models
2 from django.conf import settings
3 from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model
4 from django.conf.urls.defaults import url, patterns
5 from django.http import Http404, HttpResponse
6 from datetime import datetime
7
8
9 class Blog(Entity, Titled):
10         @property
11         def entry_tags(self):
12                 """ Returns a QuerySet of Tags that are used on any entries in this blog. """
13                 return Tag.objects.filter(blogentries__blog=self)
14
15
16 class BlogEntry(Entity, Titled):
17         blog = models.ForeignKey(Blog, related_name='entries')
18         author = models.ForeignKey(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'), related_name='blogentries')
19         date = models.DateTimeField(default=datetime.now)
20         content = models.TextField()
21         excerpt = models.TextField()
22         tags = models.ManyToManyField(Tag, related_name='blogentries')
23         
24         class Meta:
25                 ordering = ['-date']
26                 verbose_name_plural = "blog entries"
27
28
29 register_value_model(BlogEntry)
30
31
32 class BlogView(MultiView):
33         ENTRY_PERMALINK_STYLE_CHOICES = (
34                 ('D', 'Year, month, and day'),
35                 ('M', 'Year and month'),
36                 ('Y', 'Year'),
37                 ('B', 'Custom base'),
38                 ('N', 'No base')
39         )
40         
41         blog = models.ForeignKey(Blog, related_name='blogviews')
42         
43         index_page = models.ForeignKey(Page, related_name='blog_index_related')
44         entry_page = models.ForeignKey(Page, related_name='blog_entry_related')
45         entry_archive_page = models.ForeignKey(Page, related_name='blog_entry_archive_related', null=True, blank=True)
46         tag_page = models.ForeignKey(Page, related_name='blog_tag_related')
47         tag_archive_page = models.ForeignKey(Page, related_name='blog_tag_archive_related', null=True, blank=True)
48         
49         entry_permalink_style = models.CharField(max_length=1, choices=ENTRY_PERMALINK_STYLE_CHOICES)
50         entry_permalink_base = models.CharField(max_length=255, blank=False, default='entries')
51         tag_permalink_base = models.CharField(max_length=255, blank=False, default='tags')
52         
53         @property
54         def urlpatterns(self):
55                 base_patterns = patterns('',
56                         url(r'^$', self.index_view),
57                         url((r'^(?:%s)/?$' % self.tag_permalink_base), self.tag_archive_view),
58                         url((r'^(?:%s)/(?P<tag>[-\w]+)/?$' % self.tag_permalink_base), self.tag_view)
59                 )
60                 if self.entry_permalink_style == 'D':
61                         entry_patterns = patterns('',
62                                 url(r'^(?P<year>\d{4})/?$', self.entry_archive_view),
63                                 url(r'^(?P<year>\d{4})/(?P<month>\d{2})/?$', self.entry_archive_view),
64                                 url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/?$', self.entry_archive_view),
65                                 url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[-\w]+)/?$', self.entry_view)
66                         )
67                 elif self.entry_permalink_style == 'M':
68                         entry_patterns = patterns('',
69                                 url(r'^(?P<year>\d{4})/?$', self.entry_archive_view),
70                                 url(r'^(?P<year>\d{4})/(?P<month>\d{2})/?$', self.entry_archive_view),
71                                 url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[-\w]+)/?$', self.entry_view)
72                         )
73                 elif self.entry_permalink_style == 'Y':
74                         entry_patterns = patterns('',
75                                 url(r'^(?P<year>\d{4})/?$', self.entry_archive_view),
76                                 url(r'^(?P<year>\d{4})/(?P<slug>[-\w]+)/?$', self.entry_view)
77                         )
78                 elif self.entry_permalink_style == 'B':
79                         entry_patterns = patterns('',
80                                 url((r'^(?:%s)/?$' % self.entry_permalink_base), self.entry_archive_view),
81                                 url((r'^(?:%s)/(?P<slug>[-\w]+)/?$' % self.entry_permalink_base), self.entry_view)
82                         )
83                 else:
84                         entry_patterns = patterns('',
85                                 url(r'^(?P<slug>[-\w]+)/?$', self.entry_view)
86                         )
87                 return base_patterns + entry_patterns
88         
89         def index_view(self, request, node=None, extra_context=None):
90                 context = {}
91                 context.update(extra_context or {})
92                 context.update({'blog': self.blog})
93                 return self.index_page.render_to_response(node, request, extra_context=context)
94         
95         def entry_view(self, request, slug, year=None, month=None, day=None, node=None, extra_context=None):
96                 entries = self.blog.entries.all()
97                 if year:
98                         entries = entries.filter(date__year=year)
99                 if month:
100                         entries = entries.filter(date__month=month)
101                 if day:
102                         entries = entries.filter(date__day=day)
103                 try:
104                         entry = entries.get(slug=slug)
105                 except:
106                         raise Http404
107                 context = {}
108                 context.update(extra_context or {})
109                 context.update({'blog': self.blog, 'entry': entry})
110                 return self.entry_page.render_to_response(node, request, extra_context=context)
111         
112         def entry_archive_view(self, request, year=None, month=None, day=None, node=None, extra_context=None):
113                 if not self.entry_archive_page:
114                         raise Http404
115                 entries = self.blog.entries.all()
116                 if year:
117                         entries = entries.filter(date__year=year)
118                 if month:
119                         entries = entries.filter(date__month=month)
120                 if day:
121                         entries = entries.filter(date__day=day)
122                 context = {}
123                 context.update(extra_context or {})
124                 context.update({'blog': self.blog, 'year': year, 'month': month, 'day': day, 'entries': entries})
125                 return self.entry_archive_page.render_to_response(node, request, extra_context=context)
126         
127         def tag_view(self, request, tag, node=None, extra_context=None):
128                 try:
129                         tag = self.blog.entry_tags.filter(slug=tag)
130                 except:
131                         raise Http404
132                 entries = self.blog.entries.filter(tags=tag)
133                 context = {}
134                 context.update(extra_context or {})
135                 context.update({'blog': self.blog, 'tag': tag, 'entries': entries})
136                 return self.tag_page.render_to_response(node, request, extra_context=context)
137         
138         def tag_archive_view(self, request, node=None, extra_context=None):
139                 if not self.tag_archive_page:
140                         raise Http404
141                 context = {}
142                 context.update(extra_context or {})
143                 context.update({'blog': self.blog})
144                 return self.tag_archive_page.render_to_response(node, request, extra_context=context)
145
146
147 class Newsletter(Entity, Titled):
148         pass
149
150
151 class NewsletterArticle(Entity, Titled):
152         newsletter = models.ForeignKey(Newsletter, related_name='articles')
153         authors = models.ManyToManyField(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'), related_name='newsletterarticles')
154         date = models.DateTimeField(default=datetime.now)
155         lede = models.TextField(null=True, blank=True)
156         full_text = models.TextField()
157         
158         class Meta:
159                 ordering = ['-date']
160                 unique_together = (('newsletter', 'slug'),)
161
162
163 register_value_model(NewsletterArticle)
164
165
166 class NewsletterIssue(Entity, Titled):
167         newsletter = models.ForeignKey(Newsletter, related_name='issues')
168         number = models.PositiveIntegerField()
169         articles = models.ManyToManyField(NewsletterArticle)
170         
171         class Meta:
172                 ordering = ['-number']
173                 unique_together = (('newsletter', 'number'),)
174
175
176 class NewsletterView(MultiView):
177         ARTICLE_PERMALINK_STYLE_CHOICES = (
178                 ('D', 'Year, month, and day'),
179                 ('M', 'Year and month'),
180                 ('Y', 'Year'),
181                 ('S', 'Slug only')
182         )
183         
184         newsletter = models.ForeignKey(Newsletter, related_name='newsletterviews')
185         
186         index_page = models.ForeignKey(Page, related_name='newsletter_index_related')
187         article_page = models.ForeignKey(Page, related_name='newsletter_article_related')
188         article_archive_page = models.ForeignKey(Page, related_name='newsletter_article_archive_related', null=True, blank=True)
189         issue_page = models.ForeignKey(Page, related_name='newsletter_issue_related')
190         issue_archive_page = models.ForeignKey(Page, related_name='newsletter_issue_archive_related', null=True, blank=True)
191         
192         article_permalink_style = models.CharField(max_length=1, choices=ARTICLE_PERMALINK_STYLE_CHOICES)
193         article_permalink_base = models.CharField(max_length=255, blank=False, default='articles')
194         issue_permalink_base = models.CharField(max_length=255, blank=False, default='issues')
195         
196         @property
197         def urlpatterns(self):
198                 base_patterns = patterns('',
199                         url(r'^$', self.index_view),
200                         url((r'^(?:%s)/?$' % self.issue_permalink_base), self.issue_archive_view),
201                         url((r'^(?:%s)/(?P<number>\d+)/?$' % self.issue_permalink_base), self.issue_view)
202                 )
203                 article_patterns = patterns('',
204                         url((r'^(?:%s)/?$' % self.article_permalink_base), self.article_archive_view)
205                 )
206                 if self.article_permalink_style in 'DMY':
207                         article_patterns += patterns('',
208                                 url((r'^(?:%s)/(?P<year>\d{4})/?$' % self.article_permalink_base), self.article_archive_view)
209                         )
210                         if self.article_permalink_style in 'DM':
211                                 article_patterns += patterns('',
212                                         url((r'^(?:%s)/(?P<year>\d{4})/(?P<month>\d{2})/?$' % self.article_permalink_base), self.article_archive_view)
213                                 )
214                                 if self.article_permalink_style == 'D':
215                                         article_patterns += patterns('',
216                                                 url((r'^(?:%s)/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/?$' % self.article_permalink_base), self.article_archive_view),
217                                                 url((r'^(?:%s)/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[-\w]+)/?$' % self.article_permalink_base), self.article_view)
218                                         )
219                                 else:
220                                         article_patterns += patterns('',
221                                                 url((r'^(?:%s)/(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[-\w]+)/?$' % self.article_permalink_base), self.article_view)
222                                         )
223                         else:
224                                 article_patterns += patterns('',
225                                         url((r'^(?:%s)/(?P<year>\d{4})/(?P<slug>[-\w]+)/?$' % self.article_permalink_base), self.article_view)
226                                 )
227                 else:
228                         article_patterns += patterns('',
229                                 url((r'^(?:%s)/(?P<slug>[-\w]+)/?$' % self.article_permalink_base), self.article_view)
230                         )
231                 return base_patterns + article_patterns
232         
233         def index_view(self, request, node=None, extra_context=None):
234                 context = {}
235                 context.update(extra_context or {})
236                 context.update({'newsletter': self.newsletter})
237                 return self.index_page.render_to_response(node, request, extra_context=context)
238         
239         def article_view(self, request, slug, year=None, month=None, day=None, node=None, extra_context=None):
240                 articles = self.newsletter.articles.all()
241                 if year:
242                         articles = articles.filter(date__year=year)
243                 if month:
244                         articles = articles.filter(date__month=month)
245                 if day:
246                         articles = articles.filter(date__day=day)
247                 try:
248                         article = articles.get(slug=slug)
249                 except:
250                         raise Http404
251                 context = {}
252                 context.update(extra_context or {})
253                 context.update({'newsletter': self.newsletter, 'article': article})
254                 return self.article_page.render_to_response(node, request, extra_context=context)
255         
256         def article_archive_view(self, request, year=None, month=None, day=None, node=None, extra_context=None):
257                 if not self.article_archive_page:
258                         raise Http404
259                 articles = self.newsletter.articles.all()
260                 if year:
261                         articles = articles.filter(date__year=year)
262                 if month:
263                         articles = articles.filter(date__month=month)
264                 if day:
265                         articles = articles.filter(date__day=day)
266                 context = {}
267                 context.update(extra_context or {})
268                 context.update({'newsletter': self.newsletter, 'year': year, 'month': month, 'day': day, 'articles': articles})
269                 return self.article_archive_page.render_to_response(node, request, extra_context=context)
270         
271         def issue_view(self, request, number, node=None, extra_context=None):
272                 try:
273                         issue = self.newsletter.issues.get(number=number)
274                 except:
275                         raise Http404
276                 context = {}
277                 context.update(extra_context or {})
278                 context.update({'newsletter': self.newsletter, 'issue': issue})
279                 return self.issue_page.render_to_response(node, request, extra_context=context)
280         
281         def issue_archive_view(self, request, node=None, extra_context=None):
282                 if not self.issue_archive_page:
283                         raise Http404
284                 context = {}
285                 context.update(extra_context or {})
286                 context.update({'newsletter': self.newsletter})
287                 return self.issue_archive_page.render_to_response(node, request, extra_context=context)