Commits

Luke Plant committed e22b3ec

Added sermons models, admin interface, and import routine.

Also fixed public view.

Due to big schema reworkings, this commit represents lots of commits folded
together.

Comments (0)

Files changed (9)

+from django.contrib import admin
+
+from sermons.models import Speaker, Topic, Series, Sermon
+
+
+class SpeakerAdmin(admin.ModelAdmin):
+    list_display = ['name']
+
+
+class TopicAdmin(admin.ModelAdmin):
+    list_display = ['name']
+
+
+class SeriesAdmin(admin.ModelAdmin):
+    list_display = ['name']
+
+
+class SermonAdmin(admin.ModelAdmin):
+    list_display = ['id', 'date_delivered', 'time_delivered', 'speaker', 'title', 'bible_book', 'passage', 'series', 'published']
+    date_hierarchy = 'date_delivered'
+    list_per_page = 200
+
+
+
+admin.site.register(Speaker, SpeakerAdmin)
+admin.site.register(Topic, TopicAdmin)
+admin.site.register(Series, SeriesAdmin)
+admin.site.register(Sermon, SermonAdmin)

sermons/management/__init__.py

Empty file added.

sermons/management/commands/__init__.py

Empty file added.

sermons/management/commands/import_sermons.py

+"""
+import_sermons command
+"""
+import os
+import os.path
+
+from django.core.exceptions import ValidationError
+from django.core.management.base import BaseCommand
+
+from sermons.models import Sermon, SERMONS_PATH
+
+class Command(BaseCommand):
+
+    def handle(self, *args, **options):
+        from django.conf import settings
+        sermon_dir = os.path.join(settings.MEDIA_ROOT, SERMONS_PATH)
+        sermons = []
+        errors = []
+        for f in os.listdir(sermon_dir):
+            if f.endswith('.mp3'):
+                s = Sermon(sermon=os.path.join(SERMONS_PATH, f))
+                s.load_attrs_from_filename()
+                try:
+                    s.full_clean()
+                    sermons.append(s)
+                except ValidationError as e:
+                    errors.append("%s could not be imported due to missing/bad data for fields: %s" % (f, ','.join(e.message_dict.keys())))
+
+        if len(errors) > 0:
+            for e in errors:
+                self.stderr.write(e + '\n')
+        else:
+            for s in sermons:
+                s.save()

sermons/migrations/0001_initial.py

+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding model 'Speaker'
+        db.create_table('sermons_speaker', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
+        ))
+        db.send_create_signal('sermons', ['Speaker'])
+
+        # Adding model 'Topic'
+        db.create_table('sermons_topic', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
+        ))
+        db.send_create_signal('sermons', ['Topic'])
+
+        # Adding model 'Series'
+        db.create_table('sermons_series', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
+        ))
+        db.send_create_signal('sermons', ['Series'])
+
+        # Adding model 'Sermon'
+        db.create_table('sermons_sermon', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('sermon', self.gf('django.db.models.fields.files.FileField')(max_length=255)),
+            ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sermons.Speaker'])),
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
+            ('bible_book', self.gf('django.db.models.fields.CharField')(max_length=20, blank=True)),
+            ('passage', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
+            ('series', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sermons.Series'], null=True, blank=True)),
+            ('date_delivered', self.gf('django.db.models.fields.DateField')(db_index=True)),
+            ('time_delivered', self.gf('django.db.models.fields.TimeField')(db_index=True)),
+            ('published', self.gf('django.db.models.fields.BooleanField')(default=False)),
+        ))
+        db.send_create_signal('sermons', ['Sermon'])
+
+        # Adding M2M table for field topics on 'Sermon'
+        db.create_table('sermons_sermon_topics', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('sermon', models.ForeignKey(orm['sermons.sermon'], null=False)),
+            ('topic', models.ForeignKey(orm['sermons.topic'], null=False))
+        ))
+        db.create_unique('sermons_sermon_topics', ['sermon_id', 'topic_id'])
+
+
+    def backwards(self, orm):
+        
+        # Deleting model 'Speaker'
+        db.delete_table('sermons_speaker')
+
+        # Deleting model 'Topic'
+        db.delete_table('sermons_topic')
+
+        # Deleting model 'Series'
+        db.delete_table('sermons_series')
+
+        # Deleting model 'Sermon'
+        db.delete_table('sermons_sermon')
+
+        # Removing M2M table for field topics on 'Sermon'
+        db.delete_table('sermons_sermon_topics')
+
+
+    models = {
+        'sermons.series': {
+            'Meta': {'ordering': "['name']", 'object_name': 'Series'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
+        },
+        'sermons.sermon': {
+            'Meta': {'ordering': "['-date_delivered', 'time_delivered']", 'object_name': 'Sermon'},
+            'bible_book': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
+            'date_delivered': ('django.db.models.fields.DateField', [], {'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'passage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'series': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sermons.Series']", 'null': 'True', 'blank': 'True'}),
+            'sermon': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
+            'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sermons.Speaker']"}),
+            'time_delivered': ('django.db.models.fields.TimeField', [], {'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'topics': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sermons.Topic']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        'sermons.speaker': {
+            'Meta': {'ordering': "['name']", 'object_name': 'Speaker'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
+        },
+        'sermons.topic': {
+            'Meta': {'ordering': "['name']", 'object_name': 'Topic'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
+        }
+    }
+
+    complete_apps = ['sermons']

sermons/migrations/__init__.py

Empty file added.

sermons/models.py

+from datetime import date, time
+import os
+import re
+
+from django.db import models
+
+BIBLE_BOOKS = ['Genesis', 'Exodus', 'Leviticus', 'Numbers', 'Deuteronomy', 'Joshua', 'Judges', 'Ruth', '1 Samuel', '2 Samuel', '1 Kings', '2 Kings', '1 Chronicles', '2 Chronicles', 'Ezra', 'Nehemiah', 'Esther', 'Job', 'Psalm', 'Proverbs', 'Ecclesiastes', 'Song of Solomon', 'Isaiah', 'Jeremiah', 'Lamentations', 'Ezekiel', 'Daniel', 'Hosea', 'Joel', 'Amos', 'Obadiah', 'Jonah', 'Micah', 'Nahum', 'Habakkuk', 'Zephaniah', 'Haggai', 'Zechariah', 'Malachi', 'Matthew', 'Mark', 'Luke', 'John', 'Acts', 'Romans', '1 Corinthians', '2 Corinthians', 'Galatians', 'Ephesians', 'Philippians', 'Colossians', '1 Thessalonians', '2 Thessalonians', '1 Timothy', '2 Timothy', 'Titus', 'Philemon', 'Hebrews', 'James', '1 Peter', '2 Peter', '1 John', '2 John', '3 John', 'Jude', 'Revelation']
+BIBLE_BOOKS_CHOICES = [('', '(Unspecified)')] + [(b,b) for b in BIBLE_BOOKS]
+SERMONS_PATH = 'downloads/sermons/'
+expected_filename_re = re.compile(ur'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) (?P<hour>\d{2})(?P<minute>\d{2}) (?P<speaker>[^-]+)( - (?P<title>.*))?\.mp3')
+
+
+class Speaker(models.Model):
+    name = models.CharField(max_length=255, db_index=True)
+
+    def __unicode__(self):
+        return self.name
+
+    class Meta:
+        ordering = ['name']
+
+
+class Topic(models.Model):
+    name = models.CharField(max_length=255, db_index=True)
+
+    def __unicode__(self):
+        return self.name
+
+    class Meta:
+        ordering = ['name']
+
+
+class Series(models.Model):
+    name = models.CharField(max_length=255, db_index=True)
+
+    def __unicode__(self):
+        return self.name
+
+    class Meta:
+        ordering = ['name']
+        verbose_name_plural = 'serieses'
+
+
+class SermonManager(models.Manager):
+    def get_query_set(self, *args, **kwargs):
+        return super(SermonManager, self).get_query_set(*args, **kwargs).select_related('speaker')
+
+
+class Sermon(models.Model):
+    sermon = models.FileField(upload_to=SERMONS_PATH, max_length=255)
+    speaker = models.ForeignKey(Speaker)
+    title = models.CharField(max_length=255, blank=True)
+    bible_book = models.CharField(max_length=20, choices=BIBLE_BOOKS_CHOICES, blank=True)
+    passage = models.CharField(max_length=255, blank=True)
+    topics = models.ManyToManyField(Topic, blank=True)
+    series = models.ForeignKey(Series, null=True, blank=True)
+    date_delivered = models.DateField(db_index=True)
+    time_delivered = models.TimeField(db_index=True)
+    published = models.BooleanField()
+
+    objects = SermonManager()
+
+
+    def nice_time(self):
+        t = self.time_delivered
+        if t <= time(11):
+            return "Morning service"
+        elif t >= time(17):
+            return "Evening service"
+        else:
+            return "Afternoon service"
+
+    def nice_passage(self):
+        return self.passage if self.passage else self.bible_book
+
+    def load_attrs_from_filename(self):
+        """
+        Fills in the details that can be found from the filename
+        """
+
+        filename = os.path.basename(self.sermon.name)
+        m_filename = expected_filename_re.match(filename)
+
+        if m_filename is not None:
+            d = m_filename.groupdict()
+            self.date_delivered = date(int(d['year']), int(d['month']), int(d['day']))
+            self.time_delivered = time(int(d['hour']), int(d['minute']))
+            self.speaker = Speaker.objects.get_or_create(name=d['speaker'])[0]
+            passage = None
+            title = d['title']
+            if title is None:
+                title = ''
+
+            # Now see if we can parse title to get passage info
+            book = None
+            poss_book = title.split(' ')[0]
+            poss_book_2 = ' '.join(title.split(' ')[0:2])
+            if poss_book in BIBLE_BOOKS:
+                book = poss_book
+            if poss_book_2 in BIBLE_BOOKS:
+                book = poss_book_2
+
+            if book is not None:
+                # Assume 'title' is actually a passage
+                passage = title
+                title = ''
+                self.bible_book = book
+            elif ' - ' in title:
+                title_part, passage_part = title.split(' - ', 1)
+
+                poss_book = passage_part.split(' ')[0]
+                poss_book_2 = ' '.join(passage_part.split(' ')[0:2])
+                if poss_book in BIBLE_BOOKS:
+                    book = poss_book
+                if poss_book_2 in BIBLE_BOOKS:
+                    book = poss_book_2
+                if book is not None:
+                    title = title_part
+                    passage = passage_part
+                    self.bible_book = book
+
+            self.title = title
+            if passage is not None:
+                self.passage = passage
+            return True
+        else:
+            return False
+
+
+    def __unicode__(self):
+        return "%s - %s" % (self.speaker.name, self.title)
+
+    class Meta:
+        ordering = ['-date_delivered', 'time_delivered']

sermons/templates/sermons/index.html

 {% block content %}
 {{ block.super }}
 {% for sermon in sermons %}
-  {% ifchanged sermon.date_preached %}
-  <h2>{{ sermon.date_preached|date:"F j, Y" }}</h2>
+  {% ifchanged sermon.date_delivered %}
+  <h2>{{ sermon.date_delivered|date:"F j, Y" }}</h2>
   {% endifchanged %}
-  <p>{{ sermon.nice_time }}: <a href="{{ sermon.url }}">{{ sermon.speaker }} {% if sermon.title %} - {{ sermon.title }}{% endif %}</a></p>
+  <p>{{ sermon.nice_time }}: <a href="{{ sermon.url }}">{{ sermon.speaker }} {% if sermon.title %} - {{ sermon.title }}{% endif %}{% if sermon.nice_passage %} - {{ sermon.nice_passage }}{% endif %}</a></p>
 {% endfor %}
 {% endblock %}
-from datetime import date, time
-import os
-
 from django.conf import settings
 from django.shortcuts import render
 
-class Sermon(object):
-    def __init__(self, filename):
-        # yyyy-mm-dd HHMM speaker - title.mp3
-        stem = filename.rsplit(".", 1)[0]
-        bits = stem.split(" ", 2)
-        bits2 = bits[2].split("-", 1)
-        self.date_preached = date(*map(int, bits[0].split("-")))
-        self.time_preached = time(int(bits[1][0:2]), int(bits[1][2:4]))
-        self.filename = filename
-        self.speaker = bits2[0]
-        self.title = bits2[1] if len(bits2) > 1 else ''
-
-    def nice_time(self):
-        if self.time_preached <= time(11):
-            return "Morning service"
-        elif self.time_preached >= time(17):
-            return "Evening service"
-        else:
-            return "Afternoon service"
-
-    @property
-    def url(self):
-        return settings.MEDIA_URL + "downloads/sermons/" + self.filename
-
-    def __cmp__(self, other):
-        c1 = cmp(self.date_preached, other.date_preached)
-        if c1 != 0:
-            # Descending by date
-            return -c1
-        else:
-            # Then ascending by time
-            return cmp(self.time_preached, other.time_preached)
+from sermons.models import Sermon
 
 def index(request):
-    sermons = []
-    for f in os.listdir(os.path.join(settings.MEDIA_ROOT, "downloads", "sermons")):
-        if f.endswith(".mp3"):
-            sermons.append(Sermon(f))
-
-    sermons.sort()
-
+    sermons = Sermon.objects.all()
     return render(request, "sermons/index.html", {'sermons': sermons})
-