Initial commit/enabling of the Radio app.
This commit is contained in:
parent
d985efada9
commit
0d346adee9
12 changed files with 519 additions and 0 deletions
0
savepointradio/radio/__init__.py
Normal file
0
savepointradio/radio/__init__.py
Normal file
203
savepointradio/radio/admin.py
Normal file
203
savepointradio/radio/admin.py
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.db import models
|
||||||
|
from django.forms import TextInput
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from .models import Album, Artist, Game, Song
|
||||||
|
|
||||||
|
|
||||||
|
class ArtistInline(admin.TabularInline):
|
||||||
|
model = Song.artists.through
|
||||||
|
verbose_name = 'artist'
|
||||||
|
verbose_name_plural = 'artists'
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Album)
|
||||||
|
class AlbumAdmin(admin.ModelAdmin):
|
||||||
|
# Detail List display
|
||||||
|
list_display = ('title', 'is_enabled', 'is_published')
|
||||||
|
search_fields = ['title']
|
||||||
|
actions = ['publish_items']
|
||||||
|
|
||||||
|
# Edit Form display
|
||||||
|
readonly_fields = ('created_date', 'modified_date')
|
||||||
|
fieldsets = (
|
||||||
|
('Album Disabling', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('disabled', 'disabled_date', 'disabled_reason')
|
||||||
|
}),
|
||||||
|
('Main', {
|
||||||
|
'fields': ('title', 'published_date')
|
||||||
|
}),
|
||||||
|
('Stats', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('created_date', 'modified_date')
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_enabled(self, obj):
|
||||||
|
return not obj.disabled
|
||||||
|
|
||||||
|
def is_published(self, obj):
|
||||||
|
return obj.is_published
|
||||||
|
|
||||||
|
def publish_items(self, request, queryset):
|
||||||
|
rows_updated = queryset.update(published_date=timezone.now())
|
||||||
|
if rows_updated == 1:
|
||||||
|
msg = '1 album was'
|
||||||
|
else:
|
||||||
|
msg = '{} albums were'.format(str(rows_updated))
|
||||||
|
self.message_user(request, '{} successfully published.'.format(msg))
|
||||||
|
publish_items.short_description = "Publish selected items"
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Artist)
|
||||||
|
class ArtistAdmin(admin.ModelAdmin):
|
||||||
|
# Detail List display
|
||||||
|
list_display = ('first_name',
|
||||||
|
'alias',
|
||||||
|
'last_name',
|
||||||
|
'is_enabled',
|
||||||
|
'is_published')
|
||||||
|
search_fields = ['first_name', 'alias', 'last_name']
|
||||||
|
actions = ['publish_items']
|
||||||
|
|
||||||
|
# Edit Form display
|
||||||
|
readonly_fields = ('created_date', 'modified_date')
|
||||||
|
fieldsets = (
|
||||||
|
('Artist Disabling', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('disabled', 'disabled_date', 'disabled_reason')
|
||||||
|
}),
|
||||||
|
('Main', {
|
||||||
|
'fields': ('first_name', 'alias', 'last_name', 'published_date')
|
||||||
|
}),
|
||||||
|
('Stats', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('created_date', 'modified_date')
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_enabled(self, obj):
|
||||||
|
return not obj.disabled
|
||||||
|
|
||||||
|
def is_published(self, obj):
|
||||||
|
return obj.is_published
|
||||||
|
|
||||||
|
def publish_items(self, request, queryset):
|
||||||
|
rows_updated = queryset.update(published_date=timezone.now())
|
||||||
|
if rows_updated == 1:
|
||||||
|
msg = '1 artist was'
|
||||||
|
else:
|
||||||
|
msg = '{} artists were'.format(str(rows_updated))
|
||||||
|
self.message_user(request, '{} successfully published.'.format(msg))
|
||||||
|
publish_items.short_description = "Publish selected items"
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Game)
|
||||||
|
class GameAdmin(admin.ModelAdmin):
|
||||||
|
# Detail List display
|
||||||
|
list_display = ('title', 'is_enabled', 'is_published')
|
||||||
|
search_fields = ['title']
|
||||||
|
actions = ['publish_items']
|
||||||
|
|
||||||
|
# Edit Form display
|
||||||
|
readonly_fields = ('created_date', 'modified_date')
|
||||||
|
fieldsets = (
|
||||||
|
('Game Disabling', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('disabled', 'disabled_date', 'disabled_reason')
|
||||||
|
}),
|
||||||
|
('Main', {
|
||||||
|
'fields': ('title', 'published_date')
|
||||||
|
}),
|
||||||
|
('Stats', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('created_date', 'modified_date')
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_enabled(self, obj):
|
||||||
|
return not obj.disabled
|
||||||
|
|
||||||
|
def is_published(self, obj):
|
||||||
|
return obj.is_published
|
||||||
|
|
||||||
|
def publish_items(self, request, queryset):
|
||||||
|
rows_updated = queryset.update(published_date=timezone.now())
|
||||||
|
if rows_updated == 1:
|
||||||
|
msg = '1 game was'
|
||||||
|
else:
|
||||||
|
msg = '{} games were'.format(str(rows_updated))
|
||||||
|
self.message_user(request, '{} successfully published.'.format(msg))
|
||||||
|
publish_items.short_description = "Publish selected items"
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Song)
|
||||||
|
class SongAdmin(admin.ModelAdmin):
|
||||||
|
formfield_overrides = {
|
||||||
|
models.TextField: {'widget': TextInput(attrs={'size': 160, })},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detail List display
|
||||||
|
list_display = ('title',
|
||||||
|
'game',
|
||||||
|
'artist_list',
|
||||||
|
'is_enabled',
|
||||||
|
'is_published')
|
||||||
|
search_fields = ['title']
|
||||||
|
actions = ['publish_items']
|
||||||
|
|
||||||
|
# Edit Form display
|
||||||
|
exclude = ('artists',)
|
||||||
|
readonly_fields = ('length',
|
||||||
|
'last_played',
|
||||||
|
'num_played',
|
||||||
|
'created_date',
|
||||||
|
'modified_date')
|
||||||
|
fieldsets = (
|
||||||
|
('Song Disabling', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('disabled', 'disabled_date', 'disabled_reason')
|
||||||
|
}),
|
||||||
|
('Main', {
|
||||||
|
'fields': ('song_type',
|
||||||
|
'title',
|
||||||
|
'path',
|
||||||
|
'published_date')
|
||||||
|
}),
|
||||||
|
('Stats', {
|
||||||
|
'classes': ('collapse',),
|
||||||
|
'fields': ('created_date',
|
||||||
|
'modified_date',
|
||||||
|
'last_played',
|
||||||
|
'num_played',
|
||||||
|
'length')
|
||||||
|
}),
|
||||||
|
('Album', {
|
||||||
|
'fields': ('album',)
|
||||||
|
}),
|
||||||
|
('Game', {
|
||||||
|
'fields': ('game',)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
inlines = [ArtistInline]
|
||||||
|
|
||||||
|
def artist_list(self, obj):
|
||||||
|
return ', '.join([a.full_name for a in obj.artists.all()])
|
||||||
|
|
||||||
|
def is_enabled(self, obj):
|
||||||
|
return not obj.disabled
|
||||||
|
|
||||||
|
def is_published(self, obj):
|
||||||
|
return obj.is_published
|
||||||
|
|
||||||
|
def publish_items(self, request, queryset):
|
||||||
|
rows_updated = queryset.update(published_date=timezone.now())
|
||||||
|
if rows_updated == 1:
|
||||||
|
msg = '1 song was'
|
||||||
|
else:
|
||||||
|
msg = '{} songs were'.format(str(rows_updated))
|
||||||
|
self.message_user(request, '{} successfully published.'.format(msg))
|
||||||
|
publish_items.short_description = "Publish selected items"
|
5
savepointradio/radio/apps.py
Normal file
5
savepointradio/radio/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class RadioConfig(AppConfig):
|
||||||
|
name = 'radio'
|
56
savepointradio/radio/behaviors.py
Normal file
56
savepointradio/radio/behaviors.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class Disableable(models.Model):
|
||||||
|
"""
|
||||||
|
Mixin for models that can be disabled with a specified reason.
|
||||||
|
"""
|
||||||
|
disabled = models.BooleanField(_('disabled state'), default=False)
|
||||||
|
disabled_date = models.DateTimeField(_('disabled on'),
|
||||||
|
default=None,
|
||||||
|
blank=True,
|
||||||
|
null=True)
|
||||||
|
disabled_reason = models.TextField(_('reason for disabling'), blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def disable(self, reason=''):
|
||||||
|
self.disabled = True
|
||||||
|
self.disabled_date = timezone.now()
|
||||||
|
self.disabled_reason = reason
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def enable(self):
|
||||||
|
self.disabled = False
|
||||||
|
self.disabled_date = None
|
||||||
|
self.disabled_reason = ''
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Publishable(models.Model):
|
||||||
|
"""
|
||||||
|
Mixin for models that can be published to restrict accessibility before an
|
||||||
|
appointed date/time.
|
||||||
|
"""
|
||||||
|
published_date = models.DateTimeField(_('published for listening'),
|
||||||
|
default=None,
|
||||||
|
blank=True,
|
||||||
|
null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def publish(self, date=None):
|
||||||
|
if date is None:
|
||||||
|
date = timezone.now()
|
||||||
|
self.published_date = date
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_published(self):
|
||||||
|
if self.published_date is not None:
|
||||||
|
return self.published_date < timezone.now()
|
||||||
|
return False
|
14
savepointradio/radio/managers.py
Normal file
14
savepointradio/radio/managers.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from .querysets import SongQuerySet
|
||||||
|
|
||||||
|
|
||||||
|
class SongManager(models.Manager):
|
||||||
|
"""
|
||||||
|
Custom object manager for filtering out common behaviors for a playlist.
|
||||||
|
"""
|
||||||
|
def get_queryset(self):
|
||||||
|
return SongQuerySet(self.model, using=self._db)
|
||||||
|
|
||||||
|
def available(self):
|
||||||
|
return self.get_queryset().songs().enabled().published()
|
89
savepointradio/radio/migrations/0001_initial.py
Normal file
89
savepointradio/radio/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# Generated by Django 2.0 on 2017-12-29 14:36
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Album',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(auto_now_add=True, verbose_name='added on')),
|
||||||
|
('modified_date', models.DateTimeField(auto_now=True, verbose_name='last modified')),
|
||||||
|
('disabled', models.BooleanField(default=False, verbose_name='disabled state')),
|
||||||
|
('disabled_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='disabled on')),
|
||||||
|
('disabled_reason', models.TextField(blank=True, verbose_name='reason for disabling')),
|
||||||
|
('published_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='published for listening')),
|
||||||
|
('title', models.CharField(max_length=255, unique=True, verbose_name='title')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Artist',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(auto_now_add=True, verbose_name='added on')),
|
||||||
|
('modified_date', models.DateTimeField(auto_now=True, verbose_name='last modified')),
|
||||||
|
('disabled', models.BooleanField(default=False, verbose_name='disabled state')),
|
||||||
|
('disabled_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='disabled on')),
|
||||||
|
('disabled_reason', models.TextField(blank=True, verbose_name='reason for disabling')),
|
||||||
|
('published_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='published for listening')),
|
||||||
|
('alias', models.CharField(blank=True, max_length=127, verbose_name='alias')),
|
||||||
|
('first_name', models.CharField(blank=True, max_length=127, verbose_name='first name')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=127, verbose_name='last name')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Game',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(auto_now_add=True, verbose_name='added on')),
|
||||||
|
('modified_date', models.DateTimeField(auto_now=True, verbose_name='last modified')),
|
||||||
|
('disabled', models.BooleanField(default=False, verbose_name='disabled state')),
|
||||||
|
('disabled_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='disabled on')),
|
||||||
|
('disabled_reason', models.TextField(blank=True, verbose_name='reason for disabling')),
|
||||||
|
('published_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='published for listening')),
|
||||||
|
('title', models.CharField(max_length=255, unique=True, verbose_name='title')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Song',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateTimeField(auto_now_add=True, verbose_name='added on')),
|
||||||
|
('modified_date', models.DateTimeField(auto_now=True, verbose_name='last modified')),
|
||||||
|
('disabled', models.BooleanField(default=False, verbose_name='disabled state')),
|
||||||
|
('disabled_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='disabled on')),
|
||||||
|
('disabled_reason', models.TextField(blank=True, verbose_name='reason for disabling')),
|
||||||
|
('published_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='published for listening')),
|
||||||
|
('song_type', models.CharField(choices=[('J', 'Jingle'), ('S', 'Song')], default='S', max_length=1, verbose_name='song type')),
|
||||||
|
('title', models.CharField(max_length=255, verbose_name='title')),
|
||||||
|
('num_played', models.PositiveIntegerField(default=0, verbose_name='number of times played')),
|
||||||
|
('last_played', models.DateTimeField(blank=True, editable=False, null=True, verbose_name='was last played')),
|
||||||
|
('length', models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='song length (in seconds)')),
|
||||||
|
('path', models.TextField(verbose_name='absolute path to song file')),
|
||||||
|
('album', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='radio.Album')),
|
||||||
|
('artists', models.ManyToManyField(to='radio.Artist')),
|
||||||
|
('game', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='radio.Game')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
savepointradio/radio/migrations/__init__.py
Normal file
0
savepointradio/radio/migrations/__init__.py
Normal file
100
savepointradio/radio/models.py
Normal file
100
savepointradio/radio/models.py
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from core.behaviors import Timestampable
|
||||||
|
from .behaviors import Disableable, Publishable
|
||||||
|
from .managers import SongManager
|
||||||
|
|
||||||
|
|
||||||
|
class Album(Disableable, Publishable, Timestampable, models.Model):
|
||||||
|
"""
|
||||||
|
A model for a music album.
|
||||||
|
"""
|
||||||
|
title = models.CharField(_('title'), max_length=255, unique=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
|
class Artist(Disableable, Publishable, Timestampable, models.Model):
|
||||||
|
"""
|
||||||
|
A model for a music artist.
|
||||||
|
"""
|
||||||
|
alias = models.CharField(_('alias'), max_length=127, blank=True)
|
||||||
|
first_name = models.CharField(_('first name'), max_length=127, blank=True)
|
||||||
|
last_name = models.CharField(_('last name'), max_length=127, blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_name(self):
|
||||||
|
if not self.alias:
|
||||||
|
return '{} {}'.format(self.first_name, self.last_name)
|
||||||
|
else:
|
||||||
|
if not self.first_name or not self.last_name:
|
||||||
|
return self.alias
|
||||||
|
else:
|
||||||
|
return '{} "{}" {}'.format(self.first_name,
|
||||||
|
self.alias,
|
||||||
|
self.last_name)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.full_name
|
||||||
|
|
||||||
|
|
||||||
|
class Game(Disableable, Publishable, Timestampable, models.Model):
|
||||||
|
"""
|
||||||
|
A model for a game.
|
||||||
|
"""
|
||||||
|
title = models.CharField(_('title'), max_length=255, unique=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
|
class Song(Disableable, Publishable, Timestampable, models.Model):
|
||||||
|
"""
|
||||||
|
A model for a song.
|
||||||
|
"""
|
||||||
|
JINGLE = 'J'
|
||||||
|
SONG = 'S'
|
||||||
|
TYPE_CHOICES = (
|
||||||
|
(JINGLE, 'Jingle'),
|
||||||
|
(SONG, 'Song'),
|
||||||
|
)
|
||||||
|
album = models.ForeignKey(Album,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True)
|
||||||
|
artists = models.ManyToManyField(Artist)
|
||||||
|
game = models.ForeignKey(Game,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True)
|
||||||
|
song_type = models.CharField(_('song type'),
|
||||||
|
max_length=1,
|
||||||
|
choices=TYPE_CHOICES,
|
||||||
|
default=SONG)
|
||||||
|
title = models.CharField(_('title'), max_length=255)
|
||||||
|
num_played = models.PositiveIntegerField(_('number of times played'),
|
||||||
|
default=0)
|
||||||
|
last_played = models.DateTimeField(_('was last played'),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
editable=False)
|
||||||
|
length = models.DecimalField(_('song length (in seconds)'),
|
||||||
|
max_digits=8,
|
||||||
|
decimal_places=2,
|
||||||
|
null=True,
|
||||||
|
blank=True)
|
||||||
|
path = models.TextField(_('absolute path to song file'))
|
||||||
|
|
||||||
|
objects = models.Manager()
|
||||||
|
music = SongManager()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.song_type == 'J':
|
||||||
|
return self.title
|
||||||
|
else:
|
||||||
|
all_artists = ', '.join([a.full_name for a in self.artists.all()])
|
||||||
|
return '{} - {} ({})'.format(self.game.title,
|
||||||
|
self.title,
|
||||||
|
all_artists)
|
45
savepointradio/radio/querysets.py
Normal file
45
savepointradio/radio/querysets.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
|
class EnabledQuerySet(models.QuerySet):
|
||||||
|
"""
|
||||||
|
Queryset to select all objects that are not disabled.
|
||||||
|
"""
|
||||||
|
def enabled(self):
|
||||||
|
return self.filter(disabled=False)
|
||||||
|
|
||||||
|
|
||||||
|
class PublishedQuerySet(models.QuerySet):
|
||||||
|
"""
|
||||||
|
Queryset to select all objects that have been published.
|
||||||
|
"""
|
||||||
|
def published(self):
|
||||||
|
results = self.filter(
|
||||||
|
models.Q(published_date__isnull=False) &
|
||||||
|
models.Q(published_date__lte=timezone.now())
|
||||||
|
)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
class TypeQuerySet(models.QuerySet):
|
||||||
|
"""
|
||||||
|
Queryset to select all objects that are either songs or jingles.
|
||||||
|
"""
|
||||||
|
def songs(self):
|
||||||
|
return self.filter(song_type='S')
|
||||||
|
|
||||||
|
def jingles(self):
|
||||||
|
return self.filter(song_type='J')
|
||||||
|
|
||||||
|
|
||||||
|
class SongQuerySet(EnabledQuerySet,
|
||||||
|
PublishedQuerySet,
|
||||||
|
TypeQuerySet):
|
||||||
|
"""
|
||||||
|
Queryset combination that can easily select enabled objects, published
|
||||||
|
objects, and objects of a certain song type.
|
||||||
|
"""
|
||||||
|
pass
|
3
savepointradio/radio/tests.py
Normal file
3
savepointradio/radio/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
3
savepointradio/radio/views.py
Normal file
3
savepointradio/radio/views.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
|
@ -40,6 +40,7 @@ INSTALLED_APPS = [
|
||||||
'authtools',
|
'authtools',
|
||||||
|
|
||||||
'core.apps.CoreConfig',
|
'core.apps.CoreConfig',
|
||||||
|
'radio.apps.RadioConfig',
|
||||||
]
|
]
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
Loading…
Reference in a new issue