update tracks, work on admin, fix stuff and models
This commit is contained in:
parent
b36c2f944e
commit
682d8b9189
|
@ -1,11 +1,11 @@
|
|||
import copy
|
||||
|
||||
from django.contrib import admin
|
||||
from django.forms import Textarea
|
||||
from django.db import models
|
||||
|
||||
# import autocomplete_light as al
|
||||
from suit.admin import SortableTabularInline
|
||||
|
||||
from programs.forms import *
|
||||
from programs.models import *
|
||||
|
||||
|
||||
|
@ -13,13 +13,6 @@ from programs.models import *
|
|||
# Inlines
|
||||
#
|
||||
# TODO: inherits from the corresponding admin view
|
||||
class SoundInline (admin.TabularInline):
|
||||
model = Sound
|
||||
raw_id_fields=('parent',)
|
||||
fields = ('title', 'private', 'tags', 'file', 'duration', 'fragment')
|
||||
extra = 1
|
||||
|
||||
|
||||
class ScheduleInline (admin.TabularInline):
|
||||
model = Schedule
|
||||
extra = 1
|
||||
|
@ -27,11 +20,20 @@ class ScheduleInline (admin.TabularInline):
|
|||
|
||||
class DiffusionInline (admin.TabularInline):
|
||||
model = Diffusion
|
||||
raw_id_fields=('parent',)
|
||||
fields = ('parent', 'type', 'date')
|
||||
fields = ('episode', 'type', 'begin', 'end', 'stream')
|
||||
readonly_fields = ('begin', 'end', 'stream')
|
||||
extra = 1
|
||||
|
||||
|
||||
|
||||
class TrackInline (SortableTabularInline):
|
||||
fields = ['artist', 'title', 'tags', 'position']
|
||||
form = TrackForm
|
||||
model = Track
|
||||
sortable = 'position'
|
||||
extra = 10
|
||||
|
||||
|
||||
#
|
||||
# Parents
|
||||
#
|
||||
|
@ -41,7 +43,7 @@ class MetadataAdmin (admin.ModelAdmin):
|
|||
'fields': [ 'title', 'tags' ]
|
||||
}),
|
||||
( None, {
|
||||
'fields': [ 'date' ],
|
||||
'fields': [ 'date', 'public', 'enumerable' ],
|
||||
}),
|
||||
]
|
||||
|
||||
|
@ -52,17 +54,19 @@ class MetadataAdmin (admin.ModelAdmin):
|
|||
obj.save()
|
||||
|
||||
|
||||
from autocomplete_light.contrib.taggit_field import TaggitWidget, TaggitField
|
||||
class PublicationAdmin (MetadataAdmin):
|
||||
fieldsets = copy.deepcopy(MetadataAdmin.fieldsets)
|
||||
|
||||
list_display = ('id', 'title', 'date', 'private')
|
||||
list_filter = ['date', 'private']
|
||||
list_display = ('id', 'title', 'date', 'public', 'parent')
|
||||
list_filter = ['date', 'public', 'parent', 'author']
|
||||
search_fields = ['title', 'content']
|
||||
|
||||
|
||||
fieldsets[0][1]['fields'].insert(1, 'subtitle')
|
||||
fieldsets[0][1]['fields'] += [ 'img', 'content' ]
|
||||
fieldsets[1][1]['fields'] += [ 'parent', 'private', 'can_comment' ] #, 'meta' ],
|
||||
fieldsets[1][1]['fields'] += [ 'parent' ] #, 'meta' ],
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
@ -90,17 +94,19 @@ class ProgramAdmin (PublicationAdmin):
|
|||
|
||||
class EpisodeAdmin (PublicationAdmin):
|
||||
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
||||
#inlines = [ SoundInline ]
|
||||
list_filter = ['parent'] + PublicationAdmin.list_filter
|
||||
|
||||
# FIXME later: when we have thousands of tracks
|
||||
fieldsets[0][1]['fields'] += ['tracks']
|
||||
fieldsets[0][1]['fields'] += ['sounds']
|
||||
|
||||
raw_id_fields = ('tracks', 'sounds')
|
||||
autocomplete_lookup_fields = {
|
||||
'm2m': ['tracks', 'sounds'],
|
||||
}
|
||||
inlines = (TrackInline, DiffusionInline)
|
||||
|
||||
|
||||
class DiffusionAdmin (admin.ModelAdmin):
|
||||
list_display = ('type', 'begin', 'end', 'episode', 'program', 'stream')
|
||||
list_filter = ('type', 'begin', 'program', 'stream')
|
||||
|
||||
|
||||
|
||||
|
||||
admin.site.register(Track)
|
||||
admin.site.register(Sound, SoundAdmin)
|
||||
|
@ -108,5 +114,5 @@ admin.site.register(Schedule)
|
|||
admin.site.register(Article, ArticleAdmin)
|
||||
admin.site.register(Program, ProgramAdmin)
|
||||
admin.site.register(Episode, EpisodeAdmin)
|
||||
admin.site.register(Diffusion)
|
||||
admin.site.register(Diffusion, DiffusionAdmin)
|
||||
|
||||
|
|
50
programs/autocomplete_light_registry.py
Normal file
50
programs/autocomplete_light_registry.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
import autocomplete_light.shortcuts as al
|
||||
from programs.models import *
|
||||
|
||||
from taggit.models import Tag
|
||||
al.register(Tag)
|
||||
|
||||
|
||||
class OneFieldAutocomplete(al.AutocompleteModelBase):
|
||||
choice_html_format = u'''
|
||||
<span class="block" data-value="%s">%s</span>
|
||||
'''
|
||||
|
||||
def choice_html (self, choice):
|
||||
value = choice[self.search_fields[0]]
|
||||
return self.choice_html_format % (self.choice_label(choice),
|
||||
self.choice_label(value))
|
||||
|
||||
|
||||
def choices_for_request(self):
|
||||
#if not self.request.user.is_staff:
|
||||
# self.choices = self.choices.filter(private=False)
|
||||
filter_args = { self.search_fields[0] + '__icontains': self.request.GET['q'] }
|
||||
|
||||
self.choices = self.choices.filter(**filter_args)
|
||||
self.choices = self.choices.values(self.search_fields[0]).distinct()
|
||||
return self.choices
|
||||
|
||||
|
||||
class TrackArtistAutocomplete(OneFieldAutocomplete):
|
||||
search_fields = ['artist']
|
||||
model = Track
|
||||
|
||||
al.register(TrackArtistAutocomplete)
|
||||
|
||||
|
||||
class TrackTitleAutocomplete(OneFieldAutocomplete):
|
||||
search_fields = ['title']
|
||||
model = Track
|
||||
|
||||
|
||||
al.register(TrackTitleAutocomplete)
|
||||
|
||||
|
||||
#class DiffusionAutocomplete(OneFieldAutocomplete):
|
||||
# search_fields = ['episode', 'program', 'start', 'stop']
|
||||
# model = Diffusion
|
||||
#
|
||||
#al.register(DiffusionAutocomplete)
|
||||
|
||||
|
19
programs/forms.py
Normal file
19
programs/forms.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from django import forms
|
||||
from django.contrib.admin import widgets
|
||||
|
||||
import autocomplete_light.shortcuts as al
|
||||
from autocomplete_light.contrib.taggit_field import TaggitWidget
|
||||
|
||||
from programs.models import *
|
||||
|
||||
|
||||
class TrackForm (forms.ModelForm):
|
||||
class Meta:
|
||||
model = Track
|
||||
fields = ['artist', 'title', 'tags', 'position']
|
||||
widgets = {
|
||||
'artist': al.TextWidget('TrackArtistAutocomplete'),
|
||||
'title': al.TextWidget('TrackTitleAutocomplete'),
|
||||
'tags': TaggitWidget('TagAutocomplete'),
|
||||
}
|
||||
|
|
@ -49,10 +49,10 @@ ugettext_lazy('one on two')
|
|||
|
||||
|
||||
DiffusionType = {
|
||||
'diffuse': 0x01 # the diffusion is planified or done
|
||||
, 'cancel': 0x03 # the diffusion has been canceled from grid; useful to give
|
||||
'diffuse': 0x01 # the diffusion is planified or done
|
||||
, 'scheduled': 0x02 # the diffusion been scheduled automatically
|
||||
, 'cancel': 0x03 # the diffusion has been canceled from grid; useful to give
|
||||
# the info to the users
|
||||
, 'stop': 0x04 # the diffusion been arbitrary stopped (non-stop or not)
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,10 +107,15 @@ class Metadata (Model):
|
|||
_('date')
|
||||
, default = timezone.datetime.now
|
||||
)
|
||||
private = models.BooleanField(
|
||||
_('private')
|
||||
, default = False
|
||||
, help_text = _('publication is private')
|
||||
public = models.BooleanField(
|
||||
_('public')
|
||||
, default = True
|
||||
, help_text = _('publication is public')
|
||||
)
|
||||
enumerable = models.BooleanField(
|
||||
_('enumerable')
|
||||
, default = True
|
||||
, help_text = _('publication is listable')
|
||||
)
|
||||
tags = TaggableManager(
|
||||
_('tags')
|
||||
|
@ -143,7 +148,7 @@ class Publication (Metadata):
|
|||
_('content')
|
||||
, blank = True
|
||||
)
|
||||
can_comment = models.BooleanField(
|
||||
commentable = models.BooleanField(
|
||||
_('enable comments')
|
||||
, default = True
|
||||
, help_text = _('comments are enabled on this publication')
|
||||
|
@ -209,32 +214,31 @@ class Publication (Metadata):
|
|||
# Usable models
|
||||
#
|
||||
class Track (Model):
|
||||
# There are no nice solution for M2M relations ship (even without
|
||||
# through) in django-admin. So we unfortunately need to make one-
|
||||
# to-one relations and add a position argument
|
||||
episode = models.ForeignKey(
|
||||
'Episode'
|
||||
, null = True
|
||||
)
|
||||
artist = models.CharField(
|
||||
_('artist')
|
||||
, max_length = 128
|
||||
, blank = True
|
||||
)
|
||||
title = models.CharField(
|
||||
_('title')
|
||||
, max_length = 128
|
||||
)
|
||||
version = models.CharField(
|
||||
_('version')
|
||||
, max_length = 128
|
||||
, blank = True
|
||||
, help_text = _('additional informations on that track')
|
||||
)
|
||||
tags = TaggableManager( blank = True )
|
||||
|
||||
|
||||
@staticmethod
|
||||
def autocomplete_search_fields():
|
||||
return ("artist__icontains", 'title__icontains')
|
||||
# position can be used to specify a position in seconds
|
||||
position = models.SmallIntegerField(
|
||||
default = 0
|
||||
, help_text=_('position in the playlist')
|
||||
)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return ' '.join([self.artist, ':', self.title,
|
||||
(self.version and ('(' + self.version + ')') or '') ])
|
||||
return ' '.join([self.artist, ':', self.title])
|
||||
|
||||
|
||||
class Meta:
|
||||
|
@ -532,12 +536,14 @@ class Program (Publication):
|
|||
, null = True
|
||||
, help_text = _('parent article')
|
||||
)
|
||||
|
||||
email = models.EmailField(
|
||||
_('email')
|
||||
, max_length = 128
|
||||
, null = True
|
||||
, blank = True
|
||||
)
|
||||
|
||||
url = models.URLField(
|
||||
_('website')
|
||||
, blank = True
|
||||
|
@ -567,6 +573,7 @@ class Program (Publication):
|
|||
verbose_name_plural = _('Programs')
|
||||
|
||||
|
||||
|
||||
class Episode (Publication):
|
||||
# Note:
|
||||
# We do not especially need a duration here, because even if an
|
||||
|
@ -581,11 +588,6 @@ class Episode (Publication):
|
|||
, verbose_name = _('parent')
|
||||
, help_text = _('parent program')
|
||||
)
|
||||
tracks = models.ManyToManyField(
|
||||
Track
|
||||
, blank = True
|
||||
, verbose_name = _('tracks')
|
||||
)
|
||||
sounds = models.ManyToManyField(
|
||||
Sound
|
||||
, blank = True
|
||||
|
@ -620,23 +622,24 @@ class Diffusion (Model):
|
|||
verbose_name = _('type')
|
||||
, choices = [ (y, x) for x,y in DiffusionType.items() ]
|
||||
)
|
||||
date = models.DateTimeField( _('date of diffusion start') )
|
||||
begin = models.DateTimeField( _('start of diffusion start') )
|
||||
end = models.DateTimeField( _('stop of diffusion stop') )
|
||||
stream = models.SmallIntegerField(
|
||||
verbose_name = _('stream')
|
||||
, default = 0
|
||||
, help_text = 'stream id on which the diffusion happens'
|
||||
)
|
||||
scheduled = models.BooleanField(
|
||||
verbose_name = _('scheduled')
|
||||
, default = False
|
||||
, help_text = 'diffusion generated automatically'
|
||||
)
|
||||
|
||||
|
||||
def save (self, *args, **kwargs):
|
||||
if self.episode:
|
||||
self.program = self.episode.parent
|
||||
super(Diffusion, self).save(*args, **kwargs)
|
||||
|
||||
def __str__ (self):
|
||||
return self.program.title + ' on ' + str(self.start) \
|
||||
+ str(self.type)
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Diffusion')
|
||||
|
|
|
@ -1,8 +1,33 @@
|
|||
{% extends "admin/base.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
{% include 'autocomplete_light/static.html' %}
|
||||
<style>
|
||||
|
||||
/** autocomplete override **/
|
||||
.autocomplete-light-widget .deck [data-value] .remove {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.autocomplete-light-widget .deck [data-value],
|
||||
.autocomplete-light-widget .deck .choice {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.control-group .add-related,
|
||||
.inline-group .add-related {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
|
||||
/** suit **/
|
||||
.controls textarea,
|
||||
.controls .vTextField {
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
|
||||
|
||||
/** grappelli **/
|
||||
.grp-autocomplete-wrapper-m2m:focus, .grp-autocomplete-wrapper-m2m.grp-state-focus,
|
||||
.grp-autocomplete-wrapper-m2m {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
|
@ -19,6 +44,7 @@
|
|||
float: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue
Block a user