update tracks, work on admin, fix stuff and models
This commit is contained in:
		@ -1,11 +1,11 @@
 | 
				
			|||||||
import copy
 | 
					import copy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib     import admin
 | 
					from django.contrib     import admin
 | 
				
			||||||
from django.forms       import Textarea
 | 
					 | 
				
			||||||
from django.db          import models
 | 
					from django.db          import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# import autocomplete_light as al
 | 
					from suit.admin import SortableTabularInline
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from programs.forms     import *
 | 
				
			||||||
from programs.models    import *
 | 
					from programs.models    import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,13 +13,6 @@ from programs.models    import *
 | 
				
			|||||||
# Inlines
 | 
					# Inlines
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# TODO: inherits from the corresponding admin view
 | 
					# 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):
 | 
					class ScheduleInline (admin.TabularInline):
 | 
				
			||||||
    model = Schedule
 | 
					    model = Schedule
 | 
				
			||||||
    extra = 1
 | 
					    extra = 1
 | 
				
			||||||
@ -27,11 +20,20 @@ class ScheduleInline (admin.TabularInline):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class DiffusionInline (admin.TabularInline):
 | 
					class DiffusionInline (admin.TabularInline):
 | 
				
			||||||
    model = Diffusion
 | 
					    model = Diffusion
 | 
				
			||||||
    raw_id_fields=('parent',)
 | 
					    fields = ('episode', 'type', 'begin', 'end', 'stream')
 | 
				
			||||||
    fields = ('parent', 'type', 'date')
 | 
					    readonly_fields = ('begin', 'end', 'stream')
 | 
				
			||||||
    extra = 1
 | 
					    extra = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TrackInline (SortableTabularInline):
 | 
				
			||||||
 | 
					    fields = ['artist', 'title', 'tags', 'position']
 | 
				
			||||||
 | 
					    form = TrackForm
 | 
				
			||||||
 | 
					    model = Track
 | 
				
			||||||
 | 
					    sortable = 'position'
 | 
				
			||||||
 | 
					    extra = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Parents
 | 
					# Parents
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@ -41,7 +43,7 @@ class MetadataAdmin (admin.ModelAdmin):
 | 
				
			|||||||
            'fields': [ 'title', 'tags' ]
 | 
					            'fields': [ 'title', 'tags' ]
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        ( None, {
 | 
					        ( None, {
 | 
				
			||||||
            'fields': [ 'date' ],
 | 
					            'fields': [ 'date', 'public', 'enumerable' ],
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -52,17 +54,19 @@ class MetadataAdmin (admin.ModelAdmin):
 | 
				
			|||||||
        obj.save()
 | 
					        obj.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from autocomplete_light.contrib.taggit_field import TaggitWidget, TaggitField
 | 
				
			||||||
class PublicationAdmin (MetadataAdmin):
 | 
					class PublicationAdmin (MetadataAdmin):
 | 
				
			||||||
    fieldsets = copy.deepcopy(MetadataAdmin.fieldsets)
 | 
					    fieldsets = copy.deepcopy(MetadataAdmin.fieldsets)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    list_display = ('id', 'title', 'date', 'private')
 | 
					    list_display = ('id', 'title', 'date', 'public', 'parent')
 | 
				
			||||||
    list_filter = ['date', 'private']
 | 
					    list_filter = ['date', 'public', 'parent', 'author']
 | 
				
			||||||
    search_fields = ['title', 'content']
 | 
					    search_fields = ['title', 'content']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fieldsets[0][1]['fields'].insert(1, 'subtitle')
 | 
					    fieldsets[0][1]['fields'].insert(1, 'subtitle')
 | 
				
			||||||
    fieldsets[0][1]['fields'] += [ 'img', 'content' ]
 | 
					    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):
 | 
					class EpisodeAdmin (PublicationAdmin):
 | 
				
			||||||
    fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
 | 
					    fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
 | 
				
			||||||
    #inlines             = [ SoundInline ]
 | 
					 | 
				
			||||||
    list_filter         = ['parent'] + PublicationAdmin.list_filter
 | 
					    list_filter         = ['parent'] + PublicationAdmin.list_filter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # FIXME later: when we have thousands of tracks
 | 
					 | 
				
			||||||
    fieldsets[0][1]['fields'] += ['tracks']
 | 
					 | 
				
			||||||
    fieldsets[0][1]['fields'] += ['sounds']
 | 
					    fieldsets[0][1]['fields'] += ['sounds']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    raw_id_fields = ('tracks', 'sounds')
 | 
					    inlines = (TrackInline, DiffusionInline)
 | 
				
			||||||
    autocomplete_lookup_fields = {
 | 
					
 | 
				
			||||||
        'm2m': ['tracks', 'sounds'],
 | 
					
 | 
				
			||||||
    }
 | 
					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(Track)
 | 
				
			||||||
admin.site.register(Sound, SoundAdmin)
 | 
					admin.site.register(Sound, SoundAdmin)
 | 
				
			||||||
@ -108,5 +114,5 @@ admin.site.register(Schedule)
 | 
				
			|||||||
admin.site.register(Article, ArticleAdmin)
 | 
					admin.site.register(Article, ArticleAdmin)
 | 
				
			||||||
admin.site.register(Program, ProgramAdmin)
 | 
					admin.site.register(Program, ProgramAdmin)
 | 
				
			||||||
admin.site.register(Episode, EpisodeAdmin)
 | 
					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 = {
 | 
					DiffusionType = {
 | 
				
			||||||
    'diffuse':  0x01   # the diffusion is planified or done
 | 
					    'diffuse':   0x01   # the diffusion is planified or done
 | 
				
			||||||
  , 'cancel':   0x03   # the diffusion has been canceled from grid; useful to give
 | 
					  , 'scheduled': 0x02   # the diffusion been scheduled automatically
 | 
				
			||||||
 | 
					  , 'cancel':    0x03   # the diffusion has been canceled from grid; useful to give
 | 
				
			||||||
                        # the info to the users
 | 
					                        # the info to the users
 | 
				
			||||||
  , 'stop':     0x04   # the diffusion been arbitrary stopped (non-stop or not)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -107,10 +107,15 @@ class Metadata (Model):
 | 
				
			|||||||
                      _('date')
 | 
					                      _('date')
 | 
				
			||||||
                    , default = timezone.datetime.now
 | 
					                    , default = timezone.datetime.now
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
    private     = models.BooleanField(
 | 
					    public      = models.BooleanField(
 | 
				
			||||||
                      _('private')
 | 
					                      _('public')
 | 
				
			||||||
                    , default = False
 | 
					                    , default = True
 | 
				
			||||||
                    , help_text = _('publication is private')
 | 
					                    , help_text = _('publication is public')
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					    enumerable  = models.BooleanField(
 | 
				
			||||||
 | 
					                      _('enumerable')
 | 
				
			||||||
 | 
					                    , default = True
 | 
				
			||||||
 | 
					                    , help_text = _('publication is listable')
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
    tags        = TaggableManager(
 | 
					    tags        = TaggableManager(
 | 
				
			||||||
                      _('tags')
 | 
					                      _('tags')
 | 
				
			||||||
@ -143,7 +148,7 @@ class Publication (Metadata):
 | 
				
			|||||||
                      _('content')
 | 
					                      _('content')
 | 
				
			||||||
                    , blank = True
 | 
					                    , blank = True
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
    can_comment = models.BooleanField(
 | 
					    commentable = models.BooleanField(
 | 
				
			||||||
                      _('enable comments')
 | 
					                      _('enable comments')
 | 
				
			||||||
                    , default = True
 | 
					                    , default = True
 | 
				
			||||||
                    , help_text = _('comments are enabled on this publication')
 | 
					                    , help_text = _('comments are enabled on this publication')
 | 
				
			||||||
@ -209,32 +214,31 @@ class Publication (Metadata):
 | 
				
			|||||||
# Usable models
 | 
					# Usable models
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
class Track (Model):
 | 
					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      = models.CharField(
 | 
				
			||||||
                      _('artist')
 | 
					                      _('artist')
 | 
				
			||||||
                    , max_length = 128
 | 
					                    , max_length = 128
 | 
				
			||||||
                    , blank = True
 | 
					 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
    title       = models.CharField(
 | 
					    title       = models.CharField(
 | 
				
			||||||
                      _('title')
 | 
					                      _('title')
 | 
				
			||||||
                    , max_length = 128
 | 
					                    , max_length = 128
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
    version     = models.CharField(
 | 
					 | 
				
			||||||
                      _('version')
 | 
					 | 
				
			||||||
                    , max_length = 128
 | 
					 | 
				
			||||||
                    , blank = True
 | 
					 | 
				
			||||||
                    , help_text = _('additional informations on that track')
 | 
					 | 
				
			||||||
                  )
 | 
					 | 
				
			||||||
    tags        = TaggableManager( blank = True )
 | 
					    tags        = TaggableManager( blank = True )
 | 
				
			||||||
 | 
					    # position can be used to specify a position in seconds
 | 
				
			||||||
 | 
					    position    = models.SmallIntegerField(
 | 
				
			||||||
    @staticmethod
 | 
					                      default = 0
 | 
				
			||||||
    def autocomplete_search_fields():
 | 
					                    , help_text=_('position in the playlist')
 | 
				
			||||||
        return ("artist__icontains", 'title__icontains')
 | 
					                  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return ' '.join([self.artist, ':', self.title,
 | 
					        return ' '.join([self.artist, ':', self.title])
 | 
				
			||||||
                (self.version and ('(' + self.version + ')') or '') ])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
@ -532,12 +536,14 @@ class Program (Publication):
 | 
				
			|||||||
                  , null = True
 | 
					                  , null = True
 | 
				
			||||||
                  , help_text = _('parent article')
 | 
					                  , help_text = _('parent article')
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    email       = models.EmailField(
 | 
					    email       = models.EmailField(
 | 
				
			||||||
                    _('email')
 | 
					                    _('email')
 | 
				
			||||||
                  , max_length = 128
 | 
					                  , max_length = 128
 | 
				
			||||||
                  , null = True
 | 
					                  , null = True
 | 
				
			||||||
                  , blank = True
 | 
					                  , blank = True
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    url         = models.URLField(
 | 
					    url         = models.URLField(
 | 
				
			||||||
                    _('website')
 | 
					                    _('website')
 | 
				
			||||||
                  , blank = True
 | 
					                  , blank = True
 | 
				
			||||||
@ -567,6 +573,7 @@ class Program (Publication):
 | 
				
			|||||||
        verbose_name_plural = _('Programs')
 | 
					        verbose_name_plural = _('Programs')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Episode (Publication):
 | 
					class Episode (Publication):
 | 
				
			||||||
    # Note:
 | 
					    # Note:
 | 
				
			||||||
    #   We do not especially need a duration here, because even if an
 | 
					    #   We do not especially need a duration here, because even if an
 | 
				
			||||||
@ -581,11 +588,6 @@ class Episode (Publication):
 | 
				
			|||||||
                    , verbose_name = _('parent')
 | 
					                    , verbose_name = _('parent')
 | 
				
			||||||
                    , help_text = _('parent program')
 | 
					                    , help_text = _('parent program')
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
    tracks      = models.ManyToManyField(
 | 
					 | 
				
			||||||
                      Track
 | 
					 | 
				
			||||||
                    , blank = True
 | 
					 | 
				
			||||||
                    , verbose_name = _('tracks')
 | 
					 | 
				
			||||||
                  )
 | 
					 | 
				
			||||||
    sounds      = models.ManyToManyField(
 | 
					    sounds      = models.ManyToManyField(
 | 
				
			||||||
                      Sound
 | 
					                      Sound
 | 
				
			||||||
                    , blank = True
 | 
					                    , blank = True
 | 
				
			||||||
@ -620,23 +622,24 @@ class Diffusion (Model):
 | 
				
			|||||||
                      verbose_name = _('type')
 | 
					                      verbose_name = _('type')
 | 
				
			||||||
                    , choices = [ (y, x) for x,y in DiffusionType.items() ]
 | 
					                    , 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(
 | 
					    stream      = models.SmallIntegerField(
 | 
				
			||||||
                      verbose_name = _('stream')
 | 
					                      verbose_name = _('stream')
 | 
				
			||||||
                    , default = 0
 | 
					                    , default = 0
 | 
				
			||||||
                    , help_text = 'stream id on which the diffusion happens'
 | 
					                    , 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):
 | 
					    def save (self, *args, **kwargs):
 | 
				
			||||||
        if self.episode:
 | 
					        if self.episode:
 | 
				
			||||||
            self.program = self.episode.parent
 | 
					            self.program = self.episode.parent
 | 
				
			||||||
        super(Diffusion, self).save(*args, **kwargs)
 | 
					        super(Diffusion, self).save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__ (self):
 | 
				
			||||||
 | 
					        return self.program.title + ' on ' + str(self.start) \
 | 
				
			||||||
 | 
					               + str(self.type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        verbose_name = _('Diffusion')
 | 
					        verbose_name = _('Diffusion')
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,33 @@
 | 
				
			|||||||
{% extends "admin/base.html" %}
 | 
					{% extends "admin/base.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block extrahead %}
 | 
					{% block extrahead %}
 | 
				
			||||||
 | 
					{% include 'autocomplete_light/static.html' %}
 | 
				
			||||||
<style>
 | 
					<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:focus, .grp-autocomplete-wrapper-m2m.grp-state-focus,
 | 
				
			||||||
.grp-autocomplete-wrapper-m2m {
 | 
					.grp-autocomplete-wrapper-m2m {
 | 
				
			||||||
  background: rgba(255, 255, 255, 0.2);
 | 
					  background: rgba(255, 255, 255, 0.2);
 | 
				
			||||||
@ -19,6 +44,7 @@
 | 
				
			|||||||
  float: none;
 | 
					  float: none;
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user