From a59c4a3d5ca3633e428f5e1e5b34c9b519462e0b Mon Sep 17 00:00:00 2001 From: bkfox Date: Mon, 25 May 2020 16:53:18 +0200 Subject: [PATCH] start static pages --- aircox/admin/__init__.py | 1 + aircox/admin/article.py | 3 +- aircox/admin/episode.py | 2 +- aircox/admin/page.py | 52 +++++++++++---- aircox/models/__init__.py | 2 +- aircox/models/log.py | 2 +- aircox/models/page.py | 84 ++++++++++++++++++++----- aircox/templates/admin/change_form.html | 2 - aircox/urls.py | 6 ++ 9 files changed, 117 insertions(+), 37 deletions(-) diff --git a/aircox/admin/__init__.py b/aircox/admin/__init__.py index 21436bb..ce5dc4a 100644 --- a/aircox/admin/__init__.py +++ b/aircox/admin/__init__.py @@ -1,6 +1,7 @@ from .article import ArticleAdmin from .episode import DiffusionAdmin, EpisodeAdmin from .log import LogAdmin +from .page import PageAdmin, StaticPageAdmin from .program import ProgramAdmin, ScheduleAdmin, StreamAdmin from .sound import SoundAdmin, TrackAdmin from .station import StationAdmin diff --git a/aircox/admin/article.py b/aircox/admin/article.py index 4a08dc9..b6b8b03 100644 --- a/aircox/admin/article.py +++ b/aircox/admin/article.py @@ -11,8 +11,7 @@ __all__ = ['ArticleAdmin'] @admin.register(Article) 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 diff --git a/aircox/admin/episode.py b/aircox/admin/episode.py index 81a6647..44ddf20 100644 --- a/aircox/admin/episode.py +++ b/aircox/admin/episode.py @@ -56,7 +56,7 @@ class EpisodeAdmin(PageAdmin): form = EpisodeAdminForm list_display = PageAdmin.list_display list_filter = PageAdmin.list_filter - search_fields = PageAdmin.search_fields + ['parent__title'] + search_fields = PageAdmin.search_fields + ('parent__title',) # readonly_fields = ('parent',) inlines = [TracksInline, SoundInline, DiffusionInline] diff --git a/aircox/admin/page.py b/aircox/admin/page.py index 0a252e0..b0b0e50 100644 --- a/aircox/admin/page.py +++ b/aircox/admin/page.py @@ -1,4 +1,4 @@ -import urllib +from copy import deepcopy from django.contrib import admin from django.http import QueryDict @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ from adminsortable2.admin import SortableInlineAdminMixin -from ..models import Category, NavItem, Page +from ..models import Category, NavItem, Page, StaticPage __all__ = ['CategoryAdmin', 'PageAdmin', 'NavItemInline'] @@ -22,25 +22,24 @@ class CategoryAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("title",)} -# limit category choice -class PageAdmin(admin.ModelAdmin): - list_display = ('cover_thumb', 'title', 'status', 'category', 'parent') +class BasePageAdmin(admin.ModelAdmin): + list_display = ('cover_thumb', 'title', 'status', 'parent') list_display_links = ('cover_thumb', 'title') - list_editable = ('status', 'category') - list_filter = ('status', 'category') + list_editable = ('status',) + list_filter = ('status',) prepopulated_fields = {"slug": ("title",)} # prepopulate fields using changelist's filters prepopulated_filters = ('parent',) - search_fields = ['title', 'category__title'] + search_fields = ('title',) fieldsets = [ ('', { - 'fields': ['title', 'slug', 'category', 'cover', 'content'], + 'fields': ['title', 'slug', 'cover', 'content'], }), (_('Publication Settings'), { - 'fields': ['featured', 'allow_comments', 'status', 'parent'], - 'classes': ('collapse',), + 'fields': ['status', 'parent'], + # 'classes': ('collapse',), }), ] @@ -59,10 +58,16 @@ class PageAdmin(admin.ModelAdmin): def get_common_context(self, query, extra_context=None): extra_context = extra_context or {} parent = query.get('parent', None) - if parent is not None: - extra_context['parent'] = Page.objects.get_subclass(id=parent) + 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 + 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', '')) extra_context = self.get_common_context(filters, extra_context) @@ -73,6 +78,27 @@ class PageAdmin(admin.ModelAdmin): 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): model = NavItem diff --git a/aircox/models/__init__.py b/aircox/models/__init__.py index a312fef..1e94504 100644 --- a/aircox/models/__init__.py +++ b/aircox/models/__init__.py @@ -1,5 +1,5 @@ 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 .episode import Episode, Diffusion from .log import Log diff --git a/aircox/models/log.py b/aircox/models/log.py index bb5c95a..dbde3c9 100644 --- a/aircox/models/log.py +++ b/aircox/models/log.py @@ -29,7 +29,7 @@ class LogQuerySet(models.QuerySet): start = tz.datetime.combine(date, datetime.time()) end = tz.datetime.combine(date, datetime.time(23, 59, 59, 999)) 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) def after(self, date): diff --git a/aircox/models/page.py b/aircox/models/page.py index a4e2e0a..abc5cf4 100644 --- a/aircox/models/page.py +++ b/aircox/models/page.py @@ -54,7 +54,7 @@ class PageQuerySet(InheritanceQuerySet): self.filter(parent__id=id) -class Page(models.Model): +class BasePage(models.Model): """ Base class for publishable content """ STATUS_DRAFT = 0x00 STATUS_PUBLISHED = 0x10 @@ -72,30 +72,22 @@ class Page(models.Model): status = models.PositiveSmallIntegerField( _('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( on_delete=models.SET_NULL, - verbose_name=_('Cover'), null=True, blank=True, + verbose_name=_('cover'), null=True, blank=True, ) content = RichTextField( _('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() detail_url_name = None item_template_name = 'aircox/widgets/page_item.html' + class Meta: + abstract = True + def __str__(self): return '{}'.format(self.title or self.pk) @@ -106,10 +98,6 @@ class Page(models.Model): count = Page.objects.filter(slug__startswith=self.slug).count() if 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: self.cover = self.parent.cover @@ -150,9 +138,71 @@ class Page(models.Model): 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('{}', self.url, self.text) + else: + return format_html('{}', self.url, + css_class, self.text) + + class Comment(models.Model): page = models.ForeignKey( Page, models.CASCADE, verbose_name=_('related page'), + # TODO: allow_comment filter ) nickname = models.CharField(_('nickname'), max_length=32) email = models.EmailField(_('email'), max_length=32) diff --git a/aircox/templates/admin/change_form.html b/aircox/templates/admin/change_form.html index 0a1e388..7fedf81 100644 --- a/aircox/templates/admin/change_form.html +++ b/aircox/templates/admin/change_form.html @@ -8,11 +8,9 @@ › {{ opts.app_config.verbose_name }} › {% if has_view_permission %}{{ opts.verbose_name_plural|capfirst }}{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} - {% with parent=parent|default:original.parent %} {% if parent %} › {{ parent.title }} {% endif %} - {% endwith %} › {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %} diff --git a/aircox/urls.py b/aircox/urls.py index d19d5ad..d1d5d38 100755 --- a/aircox/urls.py +++ b/aircox/urls.py @@ -60,6 +60,12 @@ urls = [ path(_('publications/'), 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//'), + views.PageDetailView.as_view(), name='page-detail'), + path(_('programs/'), views.ProgramListView.as_view(model=models.Program), name='program-list'), path(_('programs//'),