start static pages

This commit is contained in:
bkfox 2020-05-25 16:53:18 +02:00
parent c457ce873c
commit a59c4a3d5c
9 changed files with 117 additions and 37 deletions

View File

@ -1,6 +1,7 @@
from .article import ArticleAdmin from .article import ArticleAdmin
from .episode import DiffusionAdmin, EpisodeAdmin from .episode import DiffusionAdmin, EpisodeAdmin
from .log import LogAdmin from .log import LogAdmin
from .page import PageAdmin, StaticPageAdmin
from .program import ProgramAdmin, ScheduleAdmin, StreamAdmin from .program import ProgramAdmin, ScheduleAdmin, StreamAdmin
from .sound import SoundAdmin, TrackAdmin from .sound import SoundAdmin, TrackAdmin
from .station import StationAdmin from .station import StationAdmin

View File

@ -11,8 +11,7 @@ __all__ = ['ArticleAdmin']
@admin.register(Article) @admin.register(Article)
class ArticleAdmin(PageAdmin): class ArticleAdmin(PageAdmin):
list_filter = PageAdmin.list_filter search_fields = PageAdmin.search_fields + ('parent__title',)
search_fields = PageAdmin.search_fields + ['parent__title']
# TODO: readonly field # TODO: readonly field

View File

@ -56,7 +56,7 @@ class EpisodeAdmin(PageAdmin):
form = EpisodeAdminForm form = EpisodeAdminForm
list_display = PageAdmin.list_display list_display = PageAdmin.list_display
list_filter = PageAdmin.list_filter list_filter = PageAdmin.list_filter
search_fields = PageAdmin.search_fields + ['parent__title'] search_fields = PageAdmin.search_fields + ('parent__title',)
# readonly_fields = ('parent',) # readonly_fields = ('parent',)
inlines = [TracksInline, SoundInline, DiffusionInline] inlines = [TracksInline, SoundInline, DiffusionInline]

View File

@ -1,4 +1,4 @@
import urllib from copy import deepcopy
from django.contrib import admin from django.contrib import admin
from django.http import QueryDict from django.http import QueryDict
@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
from adminsortable2.admin import SortableInlineAdminMixin from adminsortable2.admin import SortableInlineAdminMixin
from ..models import Category, NavItem, Page from ..models import Category, NavItem, Page, StaticPage
__all__ = ['CategoryAdmin', 'PageAdmin', 'NavItemInline'] __all__ = ['CategoryAdmin', 'PageAdmin', 'NavItemInline']
@ -22,25 +22,24 @@ class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)} prepopulated_fields = {"slug": ("title",)}
# limit category choice class BasePageAdmin(admin.ModelAdmin):
class PageAdmin(admin.ModelAdmin): list_display = ('cover_thumb', 'title', 'status', 'parent')
list_display = ('cover_thumb', 'title', 'status', 'category', 'parent')
list_display_links = ('cover_thumb', 'title') list_display_links = ('cover_thumb', 'title')
list_editable = ('status', 'category') list_editable = ('status',)
list_filter = ('status', 'category') list_filter = ('status',)
prepopulated_fields = {"slug": ("title",)} prepopulated_fields = {"slug": ("title",)}
# prepopulate fields using changelist's filters # prepopulate fields using changelist's filters
prepopulated_filters = ('parent',) prepopulated_filters = ('parent',)
search_fields = ['title', 'category__title'] search_fields = ('title',)
fieldsets = [ fieldsets = [
('', { ('', {
'fields': ['title', 'slug', 'category', 'cover', 'content'], 'fields': ['title', 'slug', 'cover', 'content'],
}), }),
(_('Publication Settings'), { (_('Publication Settings'), {
'fields': ['featured', 'allow_comments', 'status', 'parent'], 'fields': ['status', 'parent'],
'classes': ('collapse',), # 'classes': ('collapse',),
}), }),
] ]
@ -59,10 +58,16 @@ class PageAdmin(admin.ModelAdmin):
def get_common_context(self, query, extra_context=None): def get_common_context(self, query, extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
parent = query.get('parent', None) parent = query.get('parent', None)
if parent is not None: extra_context['parent'] = None if parent is None else \
extra_context['parent'] = Page.objects.get_subclass(id=parent) Page.objects.get_subclass(id=parent)
return extra_context 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
return super().render_change_form(request, context, *args, **kwargs)
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url='', extra_context=None):
filters = QueryDict(request.GET.get('_changelist_filters', '')) filters = QueryDict(request.GET.get('_changelist_filters', ''))
extra_context = self.get_common_context(filters, extra_context) extra_context = self.get_common_context(filters, extra_context)
@ -73,6 +78,27 @@ class PageAdmin(admin.ModelAdmin):
return super().changelist_view(request, extra_context) return super().changelist_view(request, extra_context)
class PageAdmin(BasePageAdmin):
list_display = BasePageAdmin.list_display + ('category',)
list_editable = BasePageAdmin.list_editable + ('category',)
list_filter = BasePageAdmin.list_editable + ('category',)
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')
@admin.register(StaticPage)
class StaticPageAdmin(BasePageAdmin):
list_display = BasePageAdmin.list_display + ('view','menu_title')
list_editable = BasePageAdmin.list_editable + ('menu_title',)
fieldsets = deepcopy(BasePageAdmin.fieldsets)
fieldsets[0][1]['fields'].insert(fieldsets[0][1]['fields'].index('slug') + 1, 'menu_title')
fieldsets[1][1]['fields'] += ('view',)
class NavItemInline(SortableInlineAdminMixin, admin.TabularInline): class NavItemInline(SortableInlineAdminMixin, admin.TabularInline):
model = NavItem model = NavItem

View File

@ -1,5 +1,5 @@
from .article import Article from .article import Article
from .page import Category, Page, Comment, NavItem from .page import Category, Page, StaticPage, Comment, NavItem
from .program import Program, Stream, Schedule from .program import Program, Stream, Schedule
from .episode import Episode, Diffusion from .episode import Episode, Diffusion
from .log import Log from .log import Log

View File

@ -29,7 +29,7 @@ class LogQuerySet(models.QuerySet):
start = tz.datetime.combine(date, datetime.time()) start = tz.datetime.combine(date, datetime.time())
end = tz.datetime.combine(date, datetime.time(23, 59, 59, 999)) end = tz.datetime.combine(date, datetime.time(23, 59, 59, 999))
return self.filter(date__range = (start, end)) return self.filter(date__range = (start, end))
# this filter does not work with sql # this filter does not work with mysql
# return self.filter(date__date=date) # return self.filter(date__date=date)
def after(self, date): def after(self, date):

View File

@ -54,7 +54,7 @@ class PageQuerySet(InheritanceQuerySet):
self.filter(parent__id=id) self.filter(parent__id=id)
class Page(models.Model): class BasePage(models.Model):
""" Base class for publishable content """ """ Base class for publishable content """
STATUS_DRAFT = 0x00 STATUS_DRAFT = 0x00
STATUS_PUBLISHED = 0x10 STATUS_PUBLISHED = 0x10
@ -72,30 +72,22 @@ class Page(models.Model):
status = models.PositiveSmallIntegerField( status = models.PositiveSmallIntegerField(
_('status'), default=STATUS_DRAFT, choices=STATUS_CHOICES, _('status'), default=STATUS_DRAFT, choices=STATUS_CHOICES,
) )
category = models.ForeignKey(
Category, models.SET_NULL,
verbose_name=_('category'), blank=True, null=True, db_index=True
)
cover = FilerImageField( cover = FilerImageField(
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
verbose_name=_('Cover'), null=True, blank=True, verbose_name=_('cover'), null=True, blank=True,
) )
content = RichTextField( content = RichTextField(
_('content'), blank=True, null=True, _('content'), blank=True, null=True,
) )
pub_date = models.DateTimeField(blank=True, null=True)
featured = models.BooleanField(
_('featured'), default=False,
)
allow_comments = models.BooleanField(
_('allow comments'), default=True,
)
objects = PageQuerySet.as_manager() objects = PageQuerySet.as_manager()
detail_url_name = None detail_url_name = None
item_template_name = 'aircox/widgets/page_item.html' item_template_name = 'aircox/widgets/page_item.html'
class Meta:
abstract = True
def __str__(self): def __str__(self):
return '{}'.format(self.title or self.pk) return '{}'.format(self.title or self.pk)
@ -106,10 +98,6 @@ class Page(models.Model):
count = Page.objects.filter(slug__startswith=self.slug).count() count = Page.objects.filter(slug__startswith=self.slug).count()
if count: if count:
self.slug += '-' + str(count) self.slug += '-' + str(count)
if self.is_published and self.pub_date is None:
self.pub_date = tz.now()
elif not self.is_published:
self.pub_date = None
if not self.cover and self.parent: if not self.cover and self.parent:
self.cover = self.parent.cover self.cover = self.parent.cover
@ -150,9 +138,71 @@ class Page(models.Model):
return cls(**cls.get_init_kwargs_from(page, **kwargs)) return cls(**cls.get_init_kwargs_from(page, **kwargs))
class Page(BasePage):
""" Base Page model used for articles and other dated content. """
category = models.ForeignKey(
Category, models.SET_NULL,
verbose_name=_('category'), blank=True, null=True, db_index=True
)
pub_date = models.DateTimeField(blank=True, null=True)
featured = models.BooleanField(
_('featured'), default=False,
)
allow_comments = models.BooleanField(
_('allow comments'), default=True,
)
def save(self, *args, **kwargs):
if self.is_published and self.pub_date is None:
self.pub_date = tz.now()
elif not self.is_published:
self.pub_date = None
super().save(*args, **kwargs)
class StaticPage(Page):
""" Static page that eventually can be attached to a specific view. """
VIEW_HOME = 0x00
VIEW_SCHEDULE = 0x01
VIEW_LOG = 0x02
VIEW_PROGRAMS = 0x03
VIEW_EPISODES = 0x04
VIEW_ARTICLES = 0x05
VIEW_CHOICES = (
(VIEW_HOME, _('Home Page')),
(VIEW_SCHEDULE, _('Schedule Page')),
(VIEW_LOG, _('Log Page')),
(VIEW_PROGRAMS, _('Programs list')),
(VIEW_EPISODES, _('Episodes list')),
(VIEW_ARTICLES, _('Articles list')),
)
view = models.SmallIntegerField(
_('attach to'), choices=VIEW_CHOICES, blank=True, null=True,
help_text=_('display this page content to related element'),
)
menu_title = models.CharField(_('menu title'), max_length=64, blank=True, null=True)
is_active = False
def render_menu_item(self, request, css_class='', active_class=''):
if active_class and request.path.startswith(self.url):
css_class += ' ' + active_class
if not self.url:
return self.text
elif not css_class:
return format_html('<a href="{}">{}</a>', self.url, self.text)
else:
return format_html('<a href="{}" class="{}">{}</a>', self.url,
css_class, self.text)
class Comment(models.Model): class Comment(models.Model):
page = models.ForeignKey( page = models.ForeignKey(
Page, models.CASCADE, verbose_name=_('related page'), Page, models.CASCADE, verbose_name=_('related page'),
# TODO: allow_comment filter
) )
nickname = models.CharField(_('nickname'), max_length=32) nickname = models.CharField(_('nickname'), max_length=32)
email = models.EmailField(_('email'), max_length=32) email = models.EmailField(_('email'), max_length=32)

View File

@ -8,11 +8,9 @@
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a> &rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} &rsaquo; {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
{% with parent=parent|default:original.parent %}
{% if parent %} {% if parent %}
&rsaquo; <a href="{% url opts|admin_urlname:"changelist" %}?parent={{parent.id}}">{{ parent.title }}</a> &rsaquo; <a href="{% url opts|admin_urlname:"changelist" %}?parent={{parent.id}}">{{ parent.title }}</a>
{% endif %} {% endif %}
{% endwith %}
&rsaquo; {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %} &rsaquo; {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %}
</div> </div>

View File

@ -60,6 +60,12 @@ urls = [
path(_('publications/'), path(_('publications/'),
views.PageListView.as_view(model=models.Page), name='page-list'), views.PageListView.as_view(model=models.Page), name='page-list'),
path(_('pages/'),
views.PageListView.as_view(model=models.StaticPage), name='static-page-list'),
path(_('pages/<slug:slug>/'),
views.PageDetailView.as_view(), name='page-detail'),
path(_('programs/'), views.ProgramListView.as_view(model=models.Program), path(_('programs/'), views.ProgramListView.as_view(model=models.Program),
name='program-list'), name='program-list'),
path(_('programs/<slug:slug>/'), path(_('programs/<slug:slug>/'),