forked from rc/aircox
code quality
This commit is contained in:
@ -7,3 +7,18 @@ from .program import ProgramAdmin, ScheduleAdmin, StreamAdmin
|
||||
from .sound import SoundAdmin, TrackAdmin
|
||||
from .station import StationAdmin
|
||||
|
||||
__all__ = (
|
||||
"filters",
|
||||
"ArticleAdmin",
|
||||
"DiffusionAdmin",
|
||||
"EpisodeAdmin",
|
||||
"LogAdmin",
|
||||
"PageAdmin",
|
||||
"StaticPageAdmin",
|
||||
"ProgramAdmin",
|
||||
"ScheduleAdmin",
|
||||
"StreamAdmin",
|
||||
"SoundAdmin",
|
||||
"TrackAdmin",
|
||||
"StationAdmin",
|
||||
)
|
||||
|
@ -1,17 +1,12 @@
|
||||
import copy
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from ..models import Article
|
||||
from .page import PageAdmin
|
||||
|
||||
|
||||
__all__ = ['ArticleAdmin']
|
||||
__all__ = ["ArticleAdmin"]
|
||||
|
||||
|
||||
@admin.register(Article)
|
||||
class ArticleAdmin(PageAdmin):
|
||||
search_fields = PageAdmin.search_fields + ('parent__title',)
|
||||
search_fields = PageAdmin.search_fields + ("parent__title",)
|
||||
# TODO: readonly field
|
||||
|
||||
|
||||
|
@ -1,78 +1,83 @@
|
||||
from adminsortable2.admin import SortableAdminBase
|
||||
from django.contrib import admin
|
||||
from django.forms import ModelForm
|
||||
from django.utils.translation import gettext as _
|
||||
from adminsortable2.admin import SortableAdminBase
|
||||
|
||||
from ..models import Episode, Diffusion
|
||||
|
||||
from ..models import Diffusion, Episode
|
||||
from .page import PageAdmin
|
||||
from .sound import SoundInline, TrackInline
|
||||
|
||||
|
||||
class DiffusionBaseAdmin:
|
||||
fields = ('type', 'start', 'end', 'schedule')
|
||||
readonly_fields = ('schedule',)
|
||||
fields = ("type", "start", "end", "schedule")
|
||||
readonly_fields = ("schedule",)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
fields = super().get_readonly_fields(request, obj)
|
||||
if not request.user.has_perm('aircox_program.scheduling'):
|
||||
fields = fields + ('program', 'start', 'end')
|
||||
if not request.user.has_perm("aircox_program.scheduling"):
|
||||
fields = fields + ("program", "start", "end")
|
||||
return [field for field in fields if field in self.fields]
|
||||
|
||||
|
||||
@admin.register(Diffusion)
|
||||
class DiffusionAdmin(DiffusionBaseAdmin, admin.ModelAdmin):
|
||||
def start_date(self, obj):
|
||||
return obj.local_start.strftime('%Y/%m/%d %H:%M')
|
||||
start_date.short_description = _('start')
|
||||
return obj.local_start.strftime("%Y/%m/%d %H:%M")
|
||||
|
||||
start_date.short_description = _("start")
|
||||
|
||||
def end_date(self, obj):
|
||||
return obj.local_end.strftime('%H:%M')
|
||||
end_date.short_description = _('end')
|
||||
return obj.local_end.strftime("%H:%M")
|
||||
|
||||
list_display = ('episode', 'start_date', 'end_date', 'type', 'initial')
|
||||
list_filter = ('type', 'start', 'program')
|
||||
list_editable = ('type',)
|
||||
ordering = ('-start', 'id')
|
||||
end_date.short_description = _("end")
|
||||
|
||||
fields = ('type', 'start', 'end', 'initial', 'program', 'schedule')
|
||||
readonly_fields = ('schedule',)
|
||||
list_display = ("episode", "start_date", "end_date", "type", "initial")
|
||||
list_filter = ("type", "start", "program")
|
||||
list_editable = ("type",)
|
||||
ordering = ("-start", "id")
|
||||
|
||||
fields = ("type", "start", "end", "initial", "program", "schedule")
|
||||
readonly_fields = ("schedule",)
|
||||
|
||||
|
||||
class DiffusionInline(DiffusionBaseAdmin, admin.TabularInline):
|
||||
model = Diffusion
|
||||
fk_name = 'episode'
|
||||
fk_name = "episode"
|
||||
extra = 0
|
||||
|
||||
def has_add_permission(self, request, obj):
|
||||
return request.user.has_perm('aircox_program.scheduling')
|
||||
return request.user.has_perm("aircox_program.scheduling")
|
||||
|
||||
|
||||
class EpisodeAdminForm(ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['parent'].required = True
|
||||
self.fields["parent"].required = True
|
||||
|
||||
|
||||
@admin.register(Episode)
|
||||
class EpisodeAdmin(SortableAdminBase, PageAdmin):
|
||||
form = EpisodeAdminForm
|
||||
list_display = PageAdmin.list_display
|
||||
list_filter = tuple(f for f in PageAdmin.list_filter
|
||||
if f != 'pub_date') + ('diffusion__start', 'pub_date')
|
||||
search_fields = PageAdmin.search_fields + ('parent__title',)
|
||||
list_filter = tuple(
|
||||
f for f in PageAdmin.list_filter if f != "pub_date"
|
||||
) + (
|
||||
"diffusion__start",
|
||||
"pub_date",
|
||||
)
|
||||
search_fields = PageAdmin.search_fields + ("parent__title",)
|
||||
# readonly_fields = ('parent',)
|
||||
|
||||
inlines = [TrackInline, SoundInline, DiffusionInline]
|
||||
|
||||
def add_view(self, request, object_id, form_url='', context=None):
|
||||
def add_view(self, request, object_id, form_url="", context=None):
|
||||
context = context or {}
|
||||
context['init_app'] = True
|
||||
context['init_el'] = '#inline-tracks'
|
||||
context["init_app"] = True
|
||||
context["init_el"] = "#inline-tracks"
|
||||
return super().change_view(request, object_id, form_url, context)
|
||||
|
||||
def change_view(self, request, object_id, form_url='', context=None):
|
||||
def change_view(self, request, object_id, form_url="", context=None):
|
||||
context = context or {}
|
||||
context['init_app'] = True
|
||||
context['init_el'] = '#inline-tracks'
|
||||
context["init_app"] = True
|
||||
context["init_el"] = "#inline-tracks"
|
||||
return super().change_view(request, object_id, form_url, context)
|
||||
|
@ -1,63 +1,86 @@
|
||||
from django.db import models
|
||||
from django.contrib.admin import filters
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db import models
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
__all__ = ('DateFieldFilter', 'DateTimeField')
|
||||
__all__ = ("DateFieldFilter", "DateTimeFieldFilter")
|
||||
|
||||
|
||||
class DateFieldFilter(filters.FieldListFilter):
|
||||
""" Display date input """
|
||||
template = 'admin/aircox/filters/date_filter.html'
|
||||
input_type = 'date'
|
||||
"""Display date input."""
|
||||
|
||||
template = "admin/aircox/filters/date_filter.html"
|
||||
input_type = "date"
|
||||
|
||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
||||
self.field_generic = '%s__' % field_path
|
||||
self.date_params = {k: v for k, v in params.items()
|
||||
if k.startswith(self.field_generic)}
|
||||
self.field_generic = "%s__" % field_path
|
||||
self.date_params = {
|
||||
k: v for k, v in params.items() if k.startswith(self.field_generic)
|
||||
}
|
||||
|
||||
exact_lookup = 'date' if isinstance(field, models.DateTimeField) else 'exact'
|
||||
exact_lookup = (
|
||||
"date" if isinstance(field, models.DateTimeField) else "exact"
|
||||
)
|
||||
|
||||
# links as: (label, param, input_type|None, value)
|
||||
self.links = [(_('Exact'), self.field_generic + exact_lookup, self.input_type),
|
||||
(_('Since'), self.field_generic + 'gte', self.input_type),
|
||||
(_('Until'), self.field_generic + 'lte', self.input_type)]
|
||||
self.links = [
|
||||
(_("Exact"), self.field_generic + exact_lookup, self.input_type),
|
||||
(_("Since"), self.field_generic + "gte", self.input_type),
|
||||
(_("Until"), self.field_generic + "lte", self.input_type),
|
||||
]
|
||||
if field.null:
|
||||
self.links.insert(0, (_('None'), self.field_generic + 'isnull', None, '1'))
|
||||
|
||||
self.query_attrs = {k:v for k,v in request.GET.items()
|
||||
if k not in self.date_params}
|
||||
self.links.insert(
|
||||
0, (_("None"), self.field_generic + "isnull", None, "1")
|
||||
)
|
||||
|
||||
self.query_attrs = {
|
||||
k: v for k, v in request.GET.items() if k not in self.date_params
|
||||
}
|
||||
self.query_string = urlencode(self.query_attrs)
|
||||
super().__init__(field, request, params, model, model_admin, field_path)
|
||||
super().__init__(
|
||||
field, request, params, model, model_admin, field_path
|
||||
)
|
||||
|
||||
def expected_parameters(self):
|
||||
return [link[1] for link in self.links]
|
||||
|
||||
def choices(self, changelist):
|
||||
yield {'label': _('Any'),
|
||||
'type': None,
|
||||
'query_string': self.query_string}
|
||||
yield {
|
||||
"label": _("Any"),
|
||||
"type": None,
|
||||
"query_string": self.query_string,
|
||||
}
|
||||
|
||||
for link in self.links:
|
||||
value = len(link) > 3 and link[3] or self.date_params.get(link[1])
|
||||
yield {
|
||||
'label': link[0], 'name': link[1], 'value': value,
|
||||
'type': link[2],
|
||||
'query_attrs': self.query_attrs,
|
||||
'query_string': urlencode({link[1]: value}) + '&' + self.query_string
|
||||
if value else self.query_string,
|
||||
"label": link[0],
|
||||
"name": link[1],
|
||||
"value": value,
|
||||
"type": link[2],
|
||||
"query_attrs": self.query_attrs,
|
||||
"query_string": urlencode({link[1]: value})
|
||||
+ "&"
|
||||
+ self.query_string
|
||||
if value
|
||||
else self.query_string,
|
||||
}
|
||||
|
||||
|
||||
class DateTimeFieldFilter(DateFieldFilter):
|
||||
""" Display datetime input """
|
||||
input_type = 'datetime-local'
|
||||
"""Display datetime input."""
|
||||
|
||||
input_type = "datetime-local"
|
||||
|
||||
|
||||
filters.FieldListFilter.register(
|
||||
lambda f: isinstance(f, models.DateField), DateFieldFilter, take_priority=True)
|
||||
lambda f: isinstance(f, models.DateField),
|
||||
DateFieldFilter,
|
||||
take_priority=True,
|
||||
)
|
||||
|
||||
filters.FieldListFilter.register(
|
||||
lambda f: isinstance(f, models.DateTimeField), DateTimeFieldFilter, take_priority=True)
|
||||
|
||||
lambda f: isinstance(f, models.DateTimeField),
|
||||
DateTimeFieldFilter,
|
||||
take_priority=True,
|
||||
)
|
||||
|
@ -2,12 +2,10 @@ from django.contrib import admin
|
||||
|
||||
from ..models import Log
|
||||
|
||||
|
||||
__all__ = ['LogAdmin']
|
||||
__all__ = ["LogAdmin"]
|
||||
|
||||
|
||||
@admin.register(Log)
|
||||
class LogAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'date', 'station', 'source', 'type', 'comment']
|
||||
list_filter = ['date', 'source', 'station']
|
||||
|
||||
list_display = ["id", "date", "station", "source", "type", "comment"]
|
||||
list_filter = ["date", "source", "station"]
|
||||
|
@ -1,23 +1,22 @@
|
||||
class UnrelatedInlineMixin:
|
||||
"""
|
||||
Inline class that can be included in an admin change view whose model
|
||||
is not directly related to inline's model.
|
||||
"""
|
||||
"""Inline class that can be included in an admin change view whose model is
|
||||
not directly related to inline's model."""
|
||||
|
||||
view_model = None
|
||||
parent_model = None
|
||||
parent_fk = ''
|
||||
parent_fk = ""
|
||||
|
||||
def __init__(self, parent_model, admin_site):
|
||||
self.view_model = parent_model
|
||||
super().__init__(self.parent_model, admin_site)
|
||||
|
||||
def get_parent(self, view_obj):
|
||||
""" Get formset's instance from `obj` of AdminSite's change form. """
|
||||
"""Get formset's instance from `obj` of AdminSite's change form."""
|
||||
field = self.parent_model._meta.get_field(self.parent_fk).remote_field
|
||||
return getattr(view_obj, field.name, None)
|
||||
|
||||
def save_parent(self, parent, view_obj):
|
||||
""" Save formset's instance. """
|
||||
"""Save formset's instance."""
|
||||
setattr(parent, self.parent_fk, view_obj)
|
||||
parent.save()
|
||||
return parent
|
||||
@ -25,6 +24,7 @@ class UnrelatedInlineMixin:
|
||||
def get_formset(self, request, obj):
|
||||
ParentFormSet = super().get_formset(request, obj)
|
||||
inline = self
|
||||
|
||||
class FormSet(ParentFormSet):
|
||||
view_obj = None
|
||||
|
||||
@ -37,6 +37,5 @@ class UnrelatedInlineMixin:
|
||||
def save(self):
|
||||
inline.save_parent(self.instance, self.view_obj)
|
||||
return super().save()
|
||||
|
||||
return FormSet
|
||||
|
||||
|
||||
|
@ -1,74 +1,82 @@
|
||||
from copy import deepcopy
|
||||
|
||||
from adminsortable2.admin import SortableInlineAdminMixin
|
||||
from django.contrib import admin
|
||||
from django.http import QueryDict
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from adminsortable2.admin import SortableInlineAdminMixin
|
||||
|
||||
from ..models import Category, Comment, NavItem, Page, StaticPage
|
||||
|
||||
|
||||
__all__ = ('CategoryAdmin', 'PageAdmin', 'NavItemInline')
|
||||
__all__ = ("CategoryAdmin", "PageAdmin", "NavItemInline")
|
||||
|
||||
|
||||
@admin.register(Category)
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ['pk', 'title', 'slug']
|
||||
list_editable = ['title', 'slug']
|
||||
search_fields = ['title']
|
||||
fields = ['title', 'slug']
|
||||
list_display = ["pk", "title", "slug"]
|
||||
list_editable = ["title", "slug"]
|
||||
search_fields = ["title"]
|
||||
fields = ["title", "slug"]
|
||||
prepopulated_fields = {"slug": ("title",)}
|
||||
|
||||
|
||||
class BasePageAdmin(admin.ModelAdmin):
|
||||
list_display = ('cover_thumb', 'title', 'status', 'parent')
|
||||
list_display_links = ('cover_thumb', 'title')
|
||||
list_editable = ('status',)
|
||||
list_filter = ('status',)
|
||||
list_display = ("cover_thumb", "title", "status", "parent")
|
||||
list_display_links = ("cover_thumb", "title")
|
||||
list_editable = ("status",)
|
||||
list_filter = ("status",)
|
||||
prepopulated_fields = {"slug": ("title",)}
|
||||
|
||||
# prepopulate fields using changelist's filters
|
||||
prepopulated_filters = ('parent',)
|
||||
prepopulated_filters = ("parent",)
|
||||
|
||||
search_fields = ('title',)
|
||||
search_fields = ("title",)
|
||||
|
||||
fieldsets = [
|
||||
('', {
|
||||
'fields': ['title', 'slug', 'cover', 'content'],
|
||||
}),
|
||||
(_('Publication Settings'), {
|
||||
'fields': ['status', 'parent'],
|
||||
}),
|
||||
(
|
||||
"",
|
||||
{
|
||||
"fields": ["title", "slug", "cover", "content"],
|
||||
},
|
||||
),
|
||||
(
|
||||
_("Publication Settings"),
|
||||
{
|
||||
"fields": ["status", "parent"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
change_form_template = 'admin/aircox/page_change_form.html'
|
||||
change_form_template = "admin/aircox/page_change_form.html"
|
||||
|
||||
def cover_thumb(self, obj):
|
||||
return mark_safe('<img src="{}"/>'.format(obj.cover.icons['64'])) \
|
||||
if obj.cover else ''
|
||||
return (
|
||||
mark_safe('<img src="{}"/>'.format(obj.cover.icons["64"]))
|
||||
if obj.cover
|
||||
else ""
|
||||
)
|
||||
|
||||
def get_changeform_initial_data(self, request):
|
||||
data = super().get_changeform_initial_data(request)
|
||||
filters = QueryDict(request.GET.get('_changelist_filters', ''))
|
||||
data['parent'] = filters.get('parent', None)
|
||||
filters = QueryDict(request.GET.get("_changelist_filters", ""))
|
||||
data["parent"] = filters.get("parent", None)
|
||||
return data
|
||||
|
||||
def _get_common_context(self, query, extra_context=None):
|
||||
extra_context = extra_context or {}
|
||||
parent = query.get('parent', None)
|
||||
extra_context['parent'] = None if parent is None else \
|
||||
Page.objects.get_subclass(id=parent)
|
||||
parent = query.get("parent", None)
|
||||
extra_context["parent"] = (
|
||||
None if parent is None else Page.objects.get_subclass(id=parent)
|
||||
)
|
||||
return extra_context
|
||||
|
||||
def render_change_form(self, request, context, *args, **kwargs):
|
||||
if context['original'] and not 'parent' in context:
|
||||
context['parent'] = context['original'].parent
|
||||
if context["original"] and "parent" not in context:
|
||||
context["parent"] = context["original"].parent
|
||||
return super().render_change_form(request, context, *args, **kwargs)
|
||||
|
||||
def add_view(self, request, form_url='', extra_context=None):
|
||||
filters = QueryDict(request.GET.get('_changelist_filters', ''))
|
||||
def add_view(self, request, form_url="", extra_context=None):
|
||||
filters = QueryDict(request.GET.get("_changelist_filters", ""))
|
||||
extra_context = self._get_common_context(filters, extra_context)
|
||||
return super().add_view(request, form_url, extra_context)
|
||||
|
||||
@ -78,31 +86,33 @@ class BasePageAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class PageAdmin(BasePageAdmin):
|
||||
change_list_template = 'admin/aircox/page_change_list.html'
|
||||
change_list_template = "admin/aircox/page_change_list.html"
|
||||
|
||||
list_display = BasePageAdmin.list_display + ('category',)
|
||||
list_editable = BasePageAdmin.list_editable + ('category',)
|
||||
list_filter = BasePageAdmin.list_filter + ('category', 'pub_date')
|
||||
search_fields = BasePageAdmin.search_fields + ('category__title',)
|
||||
list_display = BasePageAdmin.list_display + ("category",)
|
||||
list_editable = BasePageAdmin.list_editable + ("category",)
|
||||
list_filter = BasePageAdmin.list_filter + ("category", "pub_date")
|
||||
search_fields = BasePageAdmin.search_fields + ("category__title",)
|
||||
fieldsets = deepcopy(BasePageAdmin.fieldsets)
|
||||
|
||||
fieldsets[0][1]['fields'].insert(fieldsets[0][1]['fields'].index('slug') + 1, 'category')
|
||||
fieldsets[1][1]['fields'] += ('featured', 'allow_comments')
|
||||
fieldsets[0][1]["fields"].insert(
|
||||
fieldsets[0][1]["fields"].index("slug") + 1, "category"
|
||||
)
|
||||
fieldsets[1][1]["fields"] += ("featured", "allow_comments")
|
||||
|
||||
|
||||
@admin.register(StaticPage)
|
||||
class StaticPageAdmin(BasePageAdmin):
|
||||
list_display = BasePageAdmin.list_display + ('attach_to',)
|
||||
list_display = BasePageAdmin.list_display + ("attach_to",)
|
||||
fieldsets = deepcopy(BasePageAdmin.fieldsets)
|
||||
|
||||
fieldsets[1][1]['fields'] += ('attach_to',)
|
||||
fieldsets[1][1]["fields"] += ("attach_to",)
|
||||
|
||||
|
||||
@admin.register(Comment)
|
||||
class CommentAdmin(admin.ModelAdmin):
|
||||
list_display = ('page_title', 'date', 'nickname')
|
||||
list_filter = ('date',)
|
||||
search_fields = ('page__title', 'nickname')
|
||||
list_display = ("page_title", "date", "nickname")
|
||||
list_filter = ("date",)
|
||||
search_fields = ("page__title", "nickname")
|
||||
|
||||
def page_title(self, obj):
|
||||
return obj.page.title
|
||||
|
@ -1,5 +1,3 @@
|
||||
from copy import copy
|
||||
|
||||
from django.contrib import admin
|
||||
from django.forms import ModelForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -14,20 +12,20 @@ class ScheduleInlineForm(ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.initial:
|
||||
self.fields['date'].disabled = True
|
||||
self.fields['frequency'].disabled = True
|
||||
self.fields["date"].disabled = True
|
||||
self.fields["frequency"].disabled = True
|
||||
|
||||
|
||||
class ScheduleInline(admin.TabularInline):
|
||||
model = Schedule
|
||||
form = ScheduleInlineForm
|
||||
readonly_fields = ('timezone',)
|
||||
readonly_fields = ("timezone",)
|
||||
extra = 1
|
||||
|
||||
|
||||
class StreamInline(admin.TabularInline):
|
||||
model = Stream
|
||||
fields = ['delay', 'begin', 'end']
|
||||
fields = ["delay", "begin", "end"]
|
||||
extra = 1
|
||||
|
||||
|
||||
@ -39,20 +37,23 @@ class ProgramAdmin(PageAdmin):
|
||||
schedule.boolean = True
|
||||
schedule.short_description = _("Schedule")
|
||||
|
||||
list_display = PageAdmin.list_display + ('schedule', 'station', 'active')
|
||||
list_filter = PageAdmin.list_filter + ('station', 'active')
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
search_fields = ('title',)
|
||||
list_display = PageAdmin.list_display + ("schedule", "station", "active")
|
||||
list_filter = PageAdmin.list_filter + ("station", "active")
|
||||
prepopulated_fields = {"slug": ("title",)}
|
||||
search_fields = ("title",)
|
||||
|
||||
inlines = [ScheduleInline, StreamInline]
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fields = super().get_fieldsets(request, obj)
|
||||
if request.user.has_perm('aircox.program.scheduling'):
|
||||
if request.user.has_perm("aircox.program.scheduling"):
|
||||
fields = fields + [
|
||||
(_('Program Settings'), {
|
||||
'fields': ['active', 'station', 'sync'],
|
||||
})
|
||||
(
|
||||
_("Program Settings"),
|
||||
{
|
||||
"fields": ["active", "station", "sync"],
|
||||
},
|
||||
)
|
||||
]
|
||||
return fields
|
||||
|
||||
@ -61,26 +62,32 @@ class ProgramAdmin(PageAdmin):
|
||||
class ScheduleAdmin(admin.ModelAdmin):
|
||||
def program_title(self, obj):
|
||||
return obj.program.title
|
||||
program_title.short_description = _('Program')
|
||||
|
||||
program_title.short_description = _("Program")
|
||||
|
||||
def freq(self, obj):
|
||||
return obj.get_frequency_verbose()
|
||||
freq.short_description = _('Day')
|
||||
|
||||
list_filter = ['frequency', 'program']
|
||||
list_display = ['program_title', 'freq', 'time', 'timezone', 'duration',
|
||||
'initial']
|
||||
list_editable = ['time', 'duration', 'initial']
|
||||
freq.short_description = _("Day")
|
||||
|
||||
list_filter = ["frequency", "program"]
|
||||
list_display = [
|
||||
"program_title",
|
||||
"freq",
|
||||
"time",
|
||||
"timezone",
|
||||
"duration",
|
||||
"initial",
|
||||
]
|
||||
list_editable = ["time", "duration", "initial"]
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
if obj:
|
||||
return ['program', 'date', 'frequency']
|
||||
return ["program", "date", "frequency"]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
@admin.register(Stream)
|
||||
class StreamAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'program', 'delay', 'begin', 'end')
|
||||
|
||||
|
||||
list_display = ("id", "program", "delay", "begin", "end")
|
||||
|
@ -1,40 +1,48 @@
|
||||
import math
|
||||
|
||||
from adminsortable2.admin import SortableAdminBase
|
||||
from django.contrib import admin
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from adminsortable2.admin import SortableAdminBase, SortableInlineAdminMixin
|
||||
|
||||
from ..models import Sound, Track
|
||||
|
||||
|
||||
class TrackInline(admin.TabularInline):
|
||||
template = 'admin/aircox/playlist_inline.html'
|
||||
template = "admin/aircox/playlist_inline.html"
|
||||
model = Track
|
||||
extra = 0
|
||||
fields = ('position', 'artist', 'title', 'tags', 'album', 'year', 'info')
|
||||
fields = ("position", "artist", "title", "tags", "album", "year", "info")
|
||||
|
||||
list_display = ['artist', 'album', 'title', 'tags', 'related']
|
||||
list_filter = ['artist', 'album', 'title', 'tags']
|
||||
list_display = ["artist", "album", "title", "tags", "related"]
|
||||
list_filter = ["artist", "album", "title", "tags"]
|
||||
|
||||
|
||||
class SoundTrackInline(TrackInline):
|
||||
fields = TrackInline.fields + ('timestamp',)
|
||||
fields = TrackInline.fields + ("timestamp",)
|
||||
|
||||
|
||||
class SoundInline(admin.TabularInline):
|
||||
model = Sound
|
||||
fields = ['type', 'name', 'audio', 'duration', 'is_good_quality',
|
||||
'is_public', 'is_downloadable']
|
||||
readonly_fields = ['type', 'audio', 'duration', 'is_good_quality']
|
||||
fields = [
|
||||
"type",
|
||||
"name",
|
||||
"audio",
|
||||
"duration",
|
||||
"is_good_quality",
|
||||
"is_public",
|
||||
"is_downloadable",
|
||||
]
|
||||
readonly_fields = ["type", "audio", "duration", "is_good_quality"]
|
||||
extra = 0
|
||||
max_num = 0
|
||||
|
||||
def audio(self, obj):
|
||||
return mark_safe('<audio src="{}" controls></audio>'
|
||||
.format(obj.file.url))
|
||||
audio.short_description = _('Audio')
|
||||
return mark_safe(
|
||||
'<audio src="{}" controls></audio>'.format(obj.file.url)
|
||||
)
|
||||
|
||||
audio.short_description = _("Audio")
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).available()
|
||||
@ -43,63 +51,99 @@ class SoundInline(admin.TabularInline):
|
||||
@admin.register(Sound)
|
||||
class SoundAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
fields = None
|
||||
list_display = ['id', 'name', 'related',
|
||||
'type', 'duration', 'is_public', 'is_good_quality',
|
||||
'is_downloadable', 'audio']
|
||||
list_filter = ('type', 'is_good_quality', 'is_public')
|
||||
list_editable = ['name', 'is_public', 'is_downloadable']
|
||||
|
||||
search_fields = ['name', 'program__title']
|
||||
fieldsets = [
|
||||
(None, {'fields': ['name', 'file', 'type', 'program', 'episode']}),
|
||||
(None, {'fields': ['duration', 'is_public', 'is_downloadable',
|
||||
'is_good_quality', 'mtime']}),
|
||||
list_display = [
|
||||
"id",
|
||||
"name",
|
||||
"related",
|
||||
"type",
|
||||
"duration",
|
||||
"is_public",
|
||||
"is_good_quality",
|
||||
"is_downloadable",
|
||||
"audio",
|
||||
]
|
||||
readonly_fields = ('file', 'duration', 'type')
|
||||
list_filter = ("type", "is_good_quality", "is_public")
|
||||
list_editable = ["name", "is_public", "is_downloadable"]
|
||||
|
||||
search_fields = ["name", "program__title"]
|
||||
fieldsets = [
|
||||
(None, {"fields": ["name", "file", "type", "program", "episode"]}),
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": [
|
||||
"duration",
|
||||
"is_public",
|
||||
"is_downloadable",
|
||||
"is_good_quality",
|
||||
"mtime",
|
||||
]
|
||||
},
|
||||
),
|
||||
]
|
||||
readonly_fields = ("file", "duration", "type")
|
||||
inlines = [SoundTrackInline]
|
||||
|
||||
def related(self, obj):
|
||||
# TODO: link to episode or program edit
|
||||
return obj.episode.title if obj.episode else\
|
||||
obj.program.title if obj.program else ''
|
||||
related.short_description = _('Program / Episode')
|
||||
return (
|
||||
obj.episode.title
|
||||
if obj.episode
|
||||
else obj.program.title
|
||||
if obj.program
|
||||
else ""
|
||||
)
|
||||
|
||||
related.short_description = _("Program / Episode")
|
||||
|
||||
def audio(self, obj):
|
||||
return mark_safe('<audio src="{}" controls></audio>'
|
||||
.format(obj.file.url)) \
|
||||
if obj.type != Sound.TYPE_REMOVED else ''
|
||||
audio.short_description = _('Audio')
|
||||
return (
|
||||
mark_safe('<audio src="{}" controls></audio>'.format(obj.file.url))
|
||||
if obj.type != Sound.TYPE_REMOVED
|
||||
else ""
|
||||
)
|
||||
|
||||
def add_view(self, request, form_url='', context=None):
|
||||
audio.short_description = _("Audio")
|
||||
|
||||
def add_view(self, request, form_url="", context=None):
|
||||
context = context or {}
|
||||
context['init_app'] = True
|
||||
context['init_el'] = '#inline-tracks'
|
||||
context['track_timestamp'] = True
|
||||
context["init_app"] = True
|
||||
context["init_el"] = "#inline-tracks"
|
||||
context["track_timestamp"] = True
|
||||
return super().add_view(request, form_url, context)
|
||||
|
||||
def change_view(self, request, object_id, form_url='', context=None):
|
||||
def change_view(self, request, object_id, form_url="", context=None):
|
||||
context = context or {}
|
||||
context['init_app'] = True
|
||||
context['init_el'] = '#inline-tracks'
|
||||
context['track_timestamp'] = True
|
||||
context["init_app"] = True
|
||||
context["init_el"] = "#inline-tracks"
|
||||
context["track_timestamp"] = True
|
||||
return super().change_view(request, object_id, form_url, context)
|
||||
|
||||
|
||||
@admin.register(Track)
|
||||
class TrackAdmin(admin.ModelAdmin):
|
||||
def tag_list(self, obj):
|
||||
return u", ".join(o.name for o in obj.tags.all())
|
||||
return ", ".join(o.name for o in obj.tags.all())
|
||||
|
||||
list_display = ['pk', 'artist', 'title', 'tag_list', 'episode',
|
||||
'sound', 'ts']
|
||||
list_editable = ['artist', 'title']
|
||||
list_filter = ['artist', 'title', 'tags']
|
||||
list_display = [
|
||||
"pk",
|
||||
"artist",
|
||||
"title",
|
||||
"tag_list",
|
||||
"episode",
|
||||
"sound",
|
||||
"ts",
|
||||
]
|
||||
list_editable = ["artist", "title"]
|
||||
list_filter = ["artist", "title", "tags"]
|
||||
|
||||
search_fields = ['artist', 'title']
|
||||
search_fields = ["artist", "title"]
|
||||
fieldsets = [
|
||||
(_('Playlist'), {'fields': ['episode', 'sound', 'position',
|
||||
'timestamp']}),
|
||||
(_('Info'), {'fields': ['artist', 'title', 'info', 'tags']}),
|
||||
(
|
||||
_("Playlist"),
|
||||
{"fields": ["episode", "sound", "position", "timestamp"]},
|
||||
),
|
||||
(_("Info"), {"fields": ["artist", "title", "info", "tags"]}),
|
||||
]
|
||||
|
||||
# TODO on edit: readonly_fields = ['episode', 'sound']
|
||||
@ -107,10 +151,10 @@ class TrackAdmin(admin.ModelAdmin):
|
||||
def ts(self, obj):
|
||||
ts = obj.timestamp
|
||||
if ts is None:
|
||||
return ''
|
||||
return ""
|
||||
h = math.floor(ts / 3600)
|
||||
m = math.floor((ts - h) / 60)
|
||||
s = ts-h*3600-m*60
|
||||
return '{:0>2}:{:0>2}:{:0>2}'.format(h, m, s)
|
||||
s = ts - h * 3600 - m * 60
|
||||
return "{:0>2}:{:0>2}:{:0>2}".format(h, m, s)
|
||||
|
||||
ts.short_description = _('timestamp')
|
||||
ts.short_description = _("timestamp")
|
||||
|
@ -1,11 +1,10 @@
|
||||
from django.contrib import admin
|
||||
from adminsortable2.admin import SortableAdminBase
|
||||
from django.contrib import admin
|
||||
|
||||
from ..models import Port, Station
|
||||
from .page import NavItemInline
|
||||
|
||||
|
||||
__all__ = ['PortInline', 'StationAdmin']
|
||||
__all__ = ["PortInline", "StationAdmin"]
|
||||
|
||||
|
||||
class PortInline(admin.StackedInline):
|
||||
@ -15,7 +14,5 @@ class PortInline(admin.StackedInline):
|
||||
|
||||
@admin.register(Station)
|
||||
class StationAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
prepopulated_fields = {"slug": ("name",)}
|
||||
inlines = (PortInline, NavItemInline)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user