work on pages, filters, lists
This commit is contained in:
parent
c68e21ee57
commit
215a6ac331
|
@ -11,11 +11,8 @@ __all__ = ['ArticleAdmin']
|
|||
|
||||
@admin.register(Article)
|
||||
class ArticleAdmin(PageAdmin):
|
||||
list_display = PageAdmin.list_display + ('program',)
|
||||
list_filter = PageAdmin.list_filter + ('program',)
|
||||
search_fields = PageAdmin.search_fields + ['program__title']
|
||||
list_filter = PageAdmin.list_filter
|
||||
search_fields = PageAdmin.search_fields + ['parent__title']
|
||||
# TODO: readonly field
|
||||
|
||||
fieldsets = copy.deepcopy(PageAdmin.fieldsets)
|
||||
fieldsets[1][1]['fields'].insert(0, 'program')
|
||||
|
||||
|
|
|
@ -48,13 +48,11 @@ class DiffusionInline(DiffusionBaseAdmin, admin.TabularInline):
|
|||
|
||||
@admin.register(Episode)
|
||||
class EpisodeAdmin(PageAdmin):
|
||||
list_display = PageAdmin.list_display + ('program',)
|
||||
list_filter = PageAdmin.list_filter + ('program',)
|
||||
search_fields = PageAdmin.search_fields + ['program__title']
|
||||
readonly_fields = ('program',)
|
||||
list_display = PageAdmin.list_display
|
||||
list_filter = PageAdmin.list_filter
|
||||
search_fields = PageAdmin.search_fields + ['parent__title']
|
||||
# readonly_fields = ('parent',)
|
||||
|
||||
fieldsets = copy.deepcopy(PageAdmin.fieldsets)
|
||||
fieldsets[1][1]['fields'].insert(0, 'program')
|
||||
inlines = [TracksInline, SoundInline, DiffusionInline]
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class CategoryAdmin(admin.ModelAdmin):
|
|||
|
||||
# limit category choice
|
||||
class PageAdmin(admin.ModelAdmin):
|
||||
list_display = ('cover_thumb', 'title', 'status', 'category')
|
||||
list_display = ('cover_thumb', 'title', 'status', 'category', 'parent')
|
||||
list_display_links = ('cover_thumb', 'title')
|
||||
list_editable = ('status', 'category')
|
||||
list_filter = ('status', 'category')
|
||||
|
@ -33,7 +33,7 @@ class PageAdmin(admin.ModelAdmin):
|
|||
'fields': ['title', 'slug', 'category', 'cover', 'content'],
|
||||
}),
|
||||
(_('Publication Settings'), {
|
||||
'fields': ['featured', 'allow_comments', 'status'],
|
||||
'fields': ['featured', 'allow_comments', 'status', 'parent'],
|
||||
'classes': ('collapse',),
|
||||
}),
|
||||
]
|
||||
|
|
|
@ -33,7 +33,8 @@ class WeekConverter:
|
|||
return datetime.datetime.strptime(value + '/1', '%G/%V/%u').date()
|
||||
|
||||
def to_url(self, value):
|
||||
return '{:04d}/{:02d}'.format(*value.isocalendar())
|
||||
return value if isinstance(value, str) else \
|
||||
'{:04d}/{:02d}'.format(*value.isocalendar())
|
||||
|
||||
|
||||
class DateConverter:
|
||||
|
@ -41,8 +42,9 @@ class DateConverter:
|
|||
regex = r'[0-9]{4}/[0-9]{2}/[0-9]{2}'
|
||||
|
||||
def to_python(self, value):
|
||||
return str_to_date(value)
|
||||
value = value.split('/')[:3]
|
||||
return datetime.date(int(value[0]), int(value[1]), int(value[2]))
|
||||
|
||||
def to_url(self, value):
|
||||
return '{:04d}/{:02d}/{:02d}'.format(value.year, value.month,
|
||||
value.day)
|
||||
return value if isinstance(value, str) else \
|
||||
'{:04d}/{:02d}/{:02d}'.format(value.year, value.month, value.day)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,28 +2,20 @@ from django.db import models
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .page import Page, PageQuerySet
|
||||
from .program import Program, InProgramQuerySet
|
||||
|
||||
|
||||
class ArticleQuerySet(InProgramQuerySet, PageQuerySet):
|
||||
pass
|
||||
from .program import Program, ProgramChildQuerySet
|
||||
|
||||
|
||||
class Article(Page):
|
||||
detail_url_name = 'article-detail'
|
||||
|
||||
program = models.ForeignKey(
|
||||
Program, models.SET_NULL,
|
||||
verbose_name=_('program'), blank=True, null=True,
|
||||
help_text=_("publish as this program's article"),
|
||||
)
|
||||
is_static = models.BooleanField(
|
||||
_('is static'), default=False,
|
||||
help_text=_('Should this article be considered as a page '
|
||||
'instead of a blog article'),
|
||||
)
|
||||
|
||||
objects = ArticleQuerySet.as_manager()
|
||||
objects = ProgramChildQuerySet.as_manager()
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Article')
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.utils.functional import cached_property
|
|||
|
||||
|
||||
from aircox import settings, utils
|
||||
from .program import Program, InProgramQuerySet, \
|
||||
from .program import Program, ProgramChildQuerySet, \
|
||||
BaseRerun, BaseRerunQuerySet
|
||||
from .page import Page, PageQuerySet
|
||||
|
||||
|
@ -16,18 +16,18 @@ from .page import Page, PageQuerySet
|
|||
__all__ = ['Episode', 'Diffusion', 'DiffusionQuerySet']
|
||||
|
||||
|
||||
class EpisodeQuerySet(PageQuerySet, InProgramQuerySet):
|
||||
pass
|
||||
|
||||
|
||||
class Episode(Page):
|
||||
program = models.ForeignKey(
|
||||
Program, models.CASCADE,
|
||||
verbose_name=_('program'),
|
||||
)
|
||||
|
||||
objects = EpisodeQuerySet.as_manager()
|
||||
objects = ProgramChildQuerySet.as_manager()
|
||||
detail_url_name = 'episode-detail'
|
||||
item_template_name = 'aircox/episode_item.html'
|
||||
|
||||
@property
|
||||
def program(self):
|
||||
return getattr(self.parent, 'program', None)
|
||||
|
||||
@program.setter
|
||||
def program(self, value):
|
||||
self.parent = value
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Episode')
|
||||
|
@ -41,6 +41,8 @@ class Episode(Page):
|
|||
def save(self, *args, **kwargs):
|
||||
if self.cover is None:
|
||||
self.cover = self.program.cover
|
||||
if self.parent is None:
|
||||
raise ValueError('missing parent program')
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
|
@ -155,6 +157,8 @@ class Diffusion(BaseRerun):
|
|||
# help_text = _('use this input port'),
|
||||
# )
|
||||
|
||||
item_template_name = 'aircox/diffusion_item.html'
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Diffusion')
|
||||
verbose_name_plural = _('Diffusions')
|
||||
|
|
|
@ -46,6 +46,11 @@ class PageQuerySet(InheritanceQuerySet):
|
|||
def trash(self):
|
||||
return self.filter(status=Page.STATUS_TRASH)
|
||||
|
||||
def parent(self, parent=None, id=None):
|
||||
""" Return pages having this parent. """
|
||||
return self.filter(parent=parent) if id is None else \
|
||||
self.filter(parent__id=id)
|
||||
|
||||
|
||||
class Page(models.Model):
|
||||
""" Base class for publishable content """
|
||||
|
@ -58,6 +63,8 @@ class Page(models.Model):
|
|||
(STATUS_TRASH, _('trash')),
|
||||
)
|
||||
|
||||
parent = models.ForeignKey('self', models.CASCADE, blank=True, null=True,
|
||||
related_name='child_set')
|
||||
title = models.CharField(max_length=128)
|
||||
slug = models.SlugField(_('slug'), blank=True, unique=True)
|
||||
status = models.PositiveSmallIntegerField(
|
||||
|
@ -74,7 +81,7 @@ class Page(models.Model):
|
|||
content = RichTextField(
|
||||
_('content'), blank=True, null=True,
|
||||
)
|
||||
date = models.DateTimeField(default=tz.now)
|
||||
pub_date = models.DateTimeField(blank=True, null=True)
|
||||
featured = models.BooleanField(
|
||||
_('featured'), default=False,
|
||||
)
|
||||
|
@ -85,17 +92,19 @@ class Page(models.Model):
|
|||
objects = PageQuerySet.as_manager()
|
||||
|
||||
detail_url_name = None
|
||||
|
||||
item_template_name = 'aircox/page_item.html'
|
||||
|
||||
def __str__(self):
|
||||
return '{}: {}'.format(self._meta.verbose_name,
|
||||
self.title or self.pk)
|
||||
return '{}'.format(self.title or self.pk)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# TODO: ensure unique slug
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.title)
|
||||
print(self.title, '--', self.slug)
|
||||
if self.is_published and self.pub_date is None:
|
||||
self.pub_date = tz.datetime.now()
|
||||
elif not self.is_published:
|
||||
self.pub_date = None
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
|
|
@ -23,7 +23,8 @@ from .station import Station
|
|||
logger = logging.getLogger('aircox')
|
||||
|
||||
|
||||
__all__ = ['Program', 'ProgramQuerySet', 'Stream', 'Schedule']
|
||||
__all__ = ['Program', 'ProgramQuerySet', 'Stream', 'Schedule',
|
||||
'ProgramChildQuerySet', 'BaseRerun', 'BaseRerunQuerySet']
|
||||
|
||||
|
||||
class ProgramQuerySet(PageQuerySet):
|
||||
|
@ -49,15 +50,8 @@ class Program(Page):
|
|||
name if it does not exists.
|
||||
"""
|
||||
# explicit foreign key in order to avoid related name clashes
|
||||
page = models.OneToOneField(
|
||||
Page, models.CASCADE,
|
||||
parent_link=True, related_name='program_page'
|
||||
)
|
||||
station = models.ForeignKey(
|
||||
Station,
|
||||
verbose_name=_('station'),
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
station = models.ForeignKey(Station, models.CASCADE,
|
||||
verbose_name=_('station'))
|
||||
active = models.BooleanField(
|
||||
_('active'),
|
||||
default=True,
|
||||
|
@ -146,10 +140,17 @@ class Program(Page):
|
|||
.update(path=Concat('path', Substr(F('path'), len(path_))))
|
||||
|
||||
|
||||
class InProgramQuerySet(models.QuerySet):
|
||||
"""
|
||||
Queryset for model having a ForeignKey field "program" to `Program`.
|
||||
"""
|
||||
class ProgramChildQuerySet(PageQuerySet):
|
||||
def station(self, station=None, id=None):
|
||||
return self.filter(parent__program__station=station) if id is None else \
|
||||
self.filter(parent__program__station__id=id)
|
||||
|
||||
def program(self, program=None, id=None):
|
||||
return self.parent(program, id)
|
||||
|
||||
|
||||
class BaseRerunQuerySet(models.QuerySet):
|
||||
""" Queryset for BaseRerun (sub)classes. """
|
||||
def station(self, station=None, id=None):
|
||||
return self.filter(program__station=station) if id is None else \
|
||||
self.filter(program__station__id=id)
|
||||
|
@ -158,9 +159,6 @@ class InProgramQuerySet(models.QuerySet):
|
|||
return self.filter(program=program) if id is None else \
|
||||
self.filter(program__id=id)
|
||||
|
||||
|
||||
class BaseRerunQuerySet(InProgramQuerySet):
|
||||
""" Queryset for BaseRerun (sub)classes. """
|
||||
def rerun(self):
|
||||
return self.filter(initial__isnull=False)
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ def schedule_pre_delete(sender, instance, *args, **kwargs):
|
|||
|
||||
@receiver(signals.post_delete, sender=Diffusion)
|
||||
def diffusion_post_delete(sender, instance, *args, **kwargs):
|
||||
Episode.objects.filter(diffusion__isnull=True, content_isnull=True,
|
||||
Episode.objects.filter(diffusion__isnull=True, content__isnull=True,
|
||||
sound__isnull=True) \
|
||||
.delete()
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
width: 100%;
|
||||
margin: 1em 0em; }
|
||||
|
||||
ul.menu-list li {
|
||||
list-style-type: none; }
|
||||
|
||||
@keyframes spinAround {
|
||||
from {
|
||||
transform: rotate(0deg); }
|
||||
|
@ -7180,6 +7183,11 @@ label.panel-block {
|
|||
.has-background-transparent {
|
||||
background-color: transparent; }
|
||||
|
||||
.is-opacity-light {
|
||||
opacity: 0.7; }
|
||||
.is-opacity-light:hover {
|
||||
opacity: 1; }
|
||||
|
||||
.navbar + .container {
|
||||
margin-top: 1em; }
|
||||
|
||||
|
@ -7192,6 +7200,29 @@ a.navbar-item.is-active {
|
|||
.navbar .navbar-dropdown {
|
||||
z-index: 2000; }
|
||||
|
||||
.navbar .navbar-split {
|
||||
margin: 0.2em 0em;
|
||||
margin-right: 1em;
|
||||
padding-right: 1em;
|
||||
border-right: 1px #b5b5b5 solid;
|
||||
display: inline-block; }
|
||||
|
||||
.navbar form {
|
||||
margin: 0em;
|
||||
padding: 0em; }
|
||||
|
||||
.filters {
|
||||
margin: 1em 0em;
|
||||
background-color: transparent;
|
||||
margin-bottom: 1em; }
|
||||
.filters .title {
|
||||
padding-right: 2em;
|
||||
margin-right: 1em;
|
||||
border-right: 1px #b5b5b5 solid;
|
||||
font-size: 1.25rem;
|
||||
color: #7a7a7a;
|
||||
font-weight: 300; }
|
||||
|
||||
/*
|
||||
.navbar-brand img {
|
||||
min-height: 6em;
|
||||
|
|
|
@ -305,7 +305,7 @@ eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./asse
|
|||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n counts: {},\n }\n },\n\n methods: {\n update() {\n const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n const counts = {};\n\n console.log(items)\n for(var item of items)\n if(item.value)\n for(var tag of item.value.split(splitReg))\n counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n this.counts = counts;\n console.log('counts', this.counts)\n }\n },\n\n mounted() {\n this.$refs.form.addEventListener('change', () => this.update())\n this.update()\n }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n counts: {},\n }\n },\n\n methods: {\n update() {\n const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n const counts = {};\n\n console.log(items)\n for(var item of items)\n if(item.value)\n for(var tag of item.value.split(splitReg))\n counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n this.counts = counts;\n }\n },\n\n mounted() {\n this.$refs.form.addEventListener('change', () => this.update())\n this.update()\n }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
|
|
@ -7162,6 +7162,11 @@ label.panel-block {
|
|||
.has-background-transparent {
|
||||
background-color: transparent; }
|
||||
|
||||
.is-opacity-light {
|
||||
opacity: 0.7; }
|
||||
.is-opacity-light:hover {
|
||||
opacity: 1; }
|
||||
|
||||
.navbar + .container {
|
||||
margin-top: 1em; }
|
||||
|
||||
|
@ -7174,6 +7179,29 @@ a.navbar-item.is-active {
|
|||
.navbar .navbar-dropdown {
|
||||
z-index: 2000; }
|
||||
|
||||
.navbar .navbar-split {
|
||||
margin: 0.2em 0em;
|
||||
margin-right: 1em;
|
||||
padding-right: 1em;
|
||||
border-right: 1px #b5b5b5 solid;
|
||||
display: inline-block; }
|
||||
|
||||
.navbar form {
|
||||
margin: 0em;
|
||||
padding: 0em; }
|
||||
|
||||
.filters {
|
||||
margin: 1em 0em;
|
||||
background-color: transparent;
|
||||
margin-bottom: 1em; }
|
||||
.filters .title {
|
||||
padding-right: 2em;
|
||||
margin-right: 1em;
|
||||
border-right: 1px #b5b5b5 solid;
|
||||
font-size: 1.25rem;
|
||||
color: #7a7a7a;
|
||||
font-weight: 300; }
|
||||
|
||||
/*
|
||||
.navbar-brand img {
|
||||
min-height: 6em;
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
{% block content %}{{ block.super }}
|
||||
{# TODO: date subtitle #}
|
||||
<a-statistics>
|
||||
<div class="columns">
|
||||
|
||||
<a-statistics class="column">
|
||||
<template v-slot:default="{counts}">
|
||||
<table class="table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
|
@ -63,6 +65,15 @@
|
|||
</template>
|
||||
</a-statistics>
|
||||
|
||||
|
||||
<nav class="column menu is-one-fifth-desktop" role="menu">
|
||||
{% with "admin:tools-stats" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% endwith %}
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<a class="navbar-link" href="{% url "admin:aircox_article_changelist" %}">{% trans "Articles" %}</a>
|
||||
<div class="navbar-dropdown is-boxed is-right">
|
||||
{% for program in programs %}
|
||||
<a class="navbar-item" href="{% url "admin:aircox_article_changelist" %}?program={{ program.pk }}">
|
||||
<a class="navbar-item" href="{% url "admin:aircox_article_changelist" %}?parent={{ program.pk }}">
|
||||
{{ program.title }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
@ -56,7 +56,7 @@
|
|||
<a class="navbar-link" href="{% url "admin:aircox_episode_changelist" %}">{% trans "Episodes" %}</a>
|
||||
<div class="navbar-dropdown is-boxed is-right">
|
||||
{% for program in programs %}
|
||||
<a class="navbar-item" href="{% url "admin:aircox_episode_changelist" %}?program={{ program.pk }}">
|
||||
<a class="navbar-item" href="{% url "admin:aircox_episode_changelist" %}?parent={{ program.pk }}">
|
||||
{{ program.title }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
{% extends "aircox/page_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block side_nav %}
|
||||
{% block sidebar %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if side_items %}
|
||||
{% if sidebar_items %}
|
||||
<section>
|
||||
<h4 class="title is-4">{% trans "Latest news" %}</h4>
|
||||
|
||||
{% for object in side_items %}
|
||||
{% for object in sidebar_items %}
|
||||
{% include "aircox/page_item.html" %}
|
||||
{% endfor %}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
Context:
|
||||
- cover: image cover
|
||||
- site: current website
|
||||
- has_filters: display filter bar (using block "filters")
|
||||
{% endcomment %}
|
||||
<html>
|
||||
<head>
|
||||
|
@ -71,19 +72,50 @@ Context:
|
|||
{% endblock %}
|
||||
</header>
|
||||
|
||||
{% if has_filters %}
|
||||
<nav class="navbar filters"
|
||||
aria-label="{% trans "list filters" %}">
|
||||
{% block filters %}{% endblock %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{% block main %}{% endblock main %}
|
||||
</main>
|
||||
|
||||
{% if show_side_nav %}
|
||||
{% if has_sidebar %}
|
||||
<aside class="column is-one-third-desktop">
|
||||
{# FIXME: block cover into side_nav one #}
|
||||
{# FIXME: block cover into sidebar one #}
|
||||
{% block cover %}
|
||||
{% if cover is not None %}
|
||||
<img class="cover" src="{{ cover.url }}" class="cover"/>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block side_nav %}
|
||||
{% block sidebar %}
|
||||
{% if sidebar_items %}
|
||||
<section>
|
||||
<h4 class="title is-4">
|
||||
{% block sidebar_title %}{% trans "Recently" %}{% endblock %}
|
||||
</h4>
|
||||
|
||||
{% for object in sidebar_items %}
|
||||
{% include "aircox/episode_item.html" %}
|
||||
{% endfor %}
|
||||
|
||||
<br>
|
||||
<nav class="pagination is-centered">
|
||||
<ul class="pagination-list">
|
||||
<li>
|
||||
<a {% if parent %}href="{% url "page-list" parent_slug=parent.slug %}"{% else %}href="{% url "page-list" %}"{% endif %}
|
||||
class="pagination-link"
|
||||
aria-label="{% trans "Show all program's diffusions" %}">
|
||||
{% trans "Show more" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
</aside>
|
||||
{% endif %}
|
||||
|
|
11
aircox/templates/aircox/diffusion_item.html
Normal file
11
aircox/templates/aircox/diffusion_item.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% comment %}
|
||||
Context:
|
||||
- object: diffusion
|
||||
- "episode_item"'s context (except object and diffusion)
|
||||
{% endcomment %}
|
||||
{% with object as diffusion %}
|
||||
{% with object.episode as object %}
|
||||
{% include "aircox/episode_item.html" %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "aircox/page.html" %}
|
||||
{% load i18n aircox %}
|
||||
{% load i18n aircox humanize %}
|
||||
|
||||
{% block title %}
|
||||
{% with station.name as station %}
|
||||
|
@ -9,17 +9,22 @@
|
|||
|
||||
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}
|
||||
|
||||
{% block main %}{{ block.super }}
|
||||
<div class="columns">
|
||||
{% block filters %}
|
||||
{% with "diffusion-list" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}{{ block.super }}
|
||||
{% with True as hide_schedule %}
|
||||
<section class="column">
|
||||
<section role="list">
|
||||
<div id="timetable-{{ date|date:"Y-m-d" }}">
|
||||
{% for diffusion in object_list %}
|
||||
<div class="columns">
|
||||
{# FIXME: opacity should work -- maybe hidden tz #}
|
||||
<div class="columns {% if diffusion.start.date != date and diffusion.start.end <= date %}is-opacity-light{% endif %}">
|
||||
<div class="column is-one-fifth has-text-right">
|
||||
<time datetime="{{ diffusion.start|date:"c" }}">
|
||||
{{ diffusion.start|date:"H:i" }} - {{ diffusion.end|date:"H:i" }}
|
||||
{{ diffusion.start|date:"d H:i" }} - {{ diffusion.end|date:"d H:i" }}
|
||||
</time>
|
||||
</div>
|
||||
<div class="column">
|
||||
|
@ -33,12 +38,10 @@
|
|||
</section>
|
||||
{% endwith %}
|
||||
|
||||
{% comment %}
|
||||
<nav class="column menu is-one-third-desktop" role="menu">
|
||||
{% with "diffusion-list" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% endwith %}
|
||||
</nav>
|
||||
{% endcomment %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -11,9 +11,7 @@ for design review.
|
|||
|
||||
{% if object|is_diffusion %}
|
||||
{% with object as diffusion %}
|
||||
{% with diffusion.episode as object %}
|
||||
{% include "aircox/episode_item.html" %}
|
||||
{% endwith %}
|
||||
{% include "aircox/diffusion_item.html" %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
{% with object.track as object %}
|
||||
|
|
|
@ -10,14 +10,17 @@
|
|||
|
||||
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}
|
||||
|
||||
{% block filters %}
|
||||
{% with "log-list" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="columns">
|
||||
|
||||
<section class="section column">
|
||||
<section>
|
||||
{# <h4 class="subtitle size-4">{{ date }}</h4> #}
|
||||
{% with True as hide_schedule %}
|
||||
<table class="table is-striped is-hoverable is-fullwidth has-background-transparent">
|
||||
<table class="table is-striped is-hoverable is-fullwidth">
|
||||
{% for object in object_list %}
|
||||
<tr>
|
||||
<td>
|
||||
|
@ -37,13 +40,5 @@
|
|||
</table>
|
||||
{% endwith %}
|
||||
</section>
|
||||
|
||||
<nav class="column menu is-one-third-desktop" role="menu">
|
||||
{% with "logs" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% endwith %}
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -2,63 +2,65 @@
|
|||
{% load i18n aircox %}
|
||||
|
||||
{% block title %}
|
||||
{{ view.model|verbose_name:True|title }}
|
||||
{% if not parent %}{{ view.model|verbose_name:True|title }}
|
||||
{% else %}
|
||||
{% with parent.title as title %}
|
||||
{% blocktrans %}Publications of {{ title }}{% endblocktrans %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block side_nav %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if filter_categories|length != 1 %}
|
||||
<section class="toolbar">
|
||||
<h4 class="subtitle is-5">{% trans "Filters" %}</h4>
|
||||
<form method="GET" action="">
|
||||
{% block list_filters %}
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">{% trans "Categories" %}</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field is-grouped is-narrow">
|
||||
<div class="control">
|
||||
{% for category in filter_categories %}
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" class="checkbox" name="categories"
|
||||
value="{{ category.slug }}"
|
||||
{% if category.slug in categories %}checked{% endif %} />
|
||||
{{ category.title }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% block filters %}
|
||||
<div class="navbar-branding">
|
||||
<h4 class="navbar-item title">{% trans "Filters" %}</h4>
|
||||
</div>
|
||||
<form method="GET" action="" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<div class="navbar-item">
|
||||
{% block list_filters %}
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">{% trans "Categories" %}</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field is-grouped is-narrow">
|
||||
<div class="control">
|
||||
{% for category in filter_categories %}
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" class="checkbox" name="categories"
|
||||
value="{{ category.slug }}"
|
||||
{% if category.slug in categories %}checked{% endif %} />
|
||||
{{ category.title }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label"></label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
<div class="control">
|
||||
<button class="button is-primary"/>{% trans "Apply" %}</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="?" class="button is-secondary">{% trans "Reset" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item">
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
<div class="control">
|
||||
<button class="button is-primary"/>{% trans "Apply" %}</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="?" class="button is-secondary">{% trans "Reset" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
<section>
|
||||
<section role="list">
|
||||
{% for object in object_list %}
|
||||
{% block list_object %}
|
||||
{% include item_template_name %}
|
||||
{% include object.item_template_name|default:item_template_name %}
|
||||
{% endblock %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
|
|
@ -1,30 +1,16 @@
|
|||
{% extends "aircox/page_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block side_nav %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if side_items %}
|
||||
<section>
|
||||
<h4 class="title is-4">{% trans "Last shows" %}</h4>
|
||||
|
||||
{% for object in side_items %}
|
||||
{% include "aircox/episode_item.html" %}
|
||||
{% endfor %}
|
||||
|
||||
<br>
|
||||
<nav class="pagination is-centered">
|
||||
<ul class="pagination-list">
|
||||
<li>
|
||||
<a href="{% url "episode-list" parent_slug=program.slug %}"
|
||||
class="pagination-link"
|
||||
aria-label="{% trans "Show all program's diffusions" %}">
|
||||
{% trans "More shows" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% block sidebar_title %}
|
||||
{% with program.title as program %}
|
||||
{% blocktrans %} Recently on {{ program }}{% endblocktrans %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with program as parent %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ Context:
|
|||
{% endcomment %}
|
||||
|
||||
<span class="has-text-info is-size-5">♬</span>
|
||||
<span>{{ track.title }}</span>
|
||||
<span>{{ object.title }}</span>
|
||||
<span class="has-text-grey-dark has-text-weight-light">
|
||||
— {{ track.artist }}
|
||||
{% if track.info %}(<i>{{ track.info }}</i>){% endif %}
|
||||
— {{ object.artist }}
|
||||
{% if object.info %}(<i>{{ object.info }}</i>){% endif %}
|
||||
</span>
|
||||
|
||||
|
|
|
@ -9,40 +9,35 @@ Context:
|
|||
|
||||
An empty date results to a title or a separator
|
||||
{% endcomment %}
|
||||
{% load i18n humanize %}
|
||||
{% load i18n %}
|
||||
|
||||
<nav class="menu is-one-third-desktop " role="menu"
|
||||
<div class="navbar-menu" role="menu"
|
||||
aria-label="{% trans "pick a date" %}">
|
||||
<p class="menu-label">{% trans "Pick a date" %}</p>
|
||||
<form action="{% url url_name %}" method="GET"
|
||||
aria-label="{% trans "Jump to date" %}">
|
||||
<div class="field has-addons">
|
||||
<div class="control has-icons-left">
|
||||
<span class="icon is-small is-left"><span class="far fa-calendar"></span></span>
|
||||
<input type="{{ date_input|default:"date" }}" class="input date"
|
||||
name="date" value="{{ date|date:"Y-m-d" }}">
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-primary">{% trans "Go" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<ul class="menu-list">
|
||||
{% for day, title in dates %}
|
||||
{% if not day %}
|
||||
{% if title %}
|
||||
</ul>
|
||||
<p class="menu-label">{{ title }}</p>
|
||||
<ul class="menu-list">
|
||||
{% else %}<hr class="dropdown-divider">{% endif %}
|
||||
{% else %}
|
||||
<li><a href="{% url url_name date=day %}" {% if day == date %}class="is-active"{% endif %}>
|
||||
{% if title %}{{ title }}{% else %}{{ day|naturalday:"l d" }}{% endif %}
|
||||
</a></li>
|
||||
{% endif %}
|
||||
<div class="navbar-start">
|
||||
{% for day in dates %}
|
||||
<a href="{% url url_name date=day %}" class="navbar-item {% if day == date %}is-active{% endif %}">
|
||||
{{ day|date:"D. d" }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item">
|
||||
<form action="{% url url_name %}" method="GET" class="navbar-body"
|
||||
aria-label="{% trans "Jump to date" %}">
|
||||
<div class="field has-addons">
|
||||
<div class="control has-icons-left">
|
||||
<span class="icon is-small is-left"><span class="far fa-calendar"></span></span>
|
||||
<input type="{{ date_input|default:"date" }}" class="input date"
|
||||
name="date" value="{{ date|date:"Y-m-d" }}">
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-primary">{% trans "Go" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ api = [
|
|||
|
||||
|
||||
urls = [
|
||||
path(_(''),
|
||||
views.DiffusionListView.as_view(), name='home'),
|
||||
path('api/', include(api)),
|
||||
|
||||
# path('', views.PageDetailView.as_view(model=models.Article),
|
||||
|
@ -35,15 +37,6 @@ urls = [
|
|||
views.ArticleDetailView.as_view(),
|
||||
name='article-detail'),
|
||||
|
||||
path(_('programs/'), views.PageListView.as_view(model=models.Program),
|
||||
name='program-list'),
|
||||
path(_('programs/<slug:slug>/'),
|
||||
views.ProgramDetailView.as_view(), name='program-detail'),
|
||||
path(_('programs/<slug:parent_slug>/episodes/'),
|
||||
views.EpisodeListView.as_view(), name='episode-list'),
|
||||
path(_('programs/<slug:parent_slug>/articles/'),
|
||||
views.ArticleListView.as_view(), name='article-list'),
|
||||
|
||||
path(_('episodes/'),
|
||||
views.EpisodeListView.as_view(), name='episode-list'),
|
||||
path(_('episodes/<slug:slug>/'),
|
||||
|
@ -53,7 +46,23 @@ urls = [
|
|||
path(_('week/<date:date>/'),
|
||||
views.DiffusionListView.as_view(), name='diffusion-list'),
|
||||
|
||||
path(_('logs/'), views.LogListView.as_view(), name='logs'),
|
||||
path(_('logs/<date:date>/'), views.LogListView.as_view(), name='logs'),
|
||||
path(_('logs/'), views.LogListView.as_view(), name='log-list'),
|
||||
path(_('logs/<date:date>/'), views.LogListView.as_view(), name='log-list'),
|
||||
# path('<page_path:path>', views.route_page, name='page'),
|
||||
|
||||
path(_('publications/'),
|
||||
views.ProgramPageListView.as_view(), name='page-list'),
|
||||
|
||||
path(_('programs/'), views.PageListView.as_view(model=models.Program),
|
||||
name='program-list'),
|
||||
path(_('programs/<slug:slug>/'),
|
||||
views.ProgramDetailView.as_view(), name='program-detail'),
|
||||
path(_('programs/<slug:parent_slug>/episodes/'),
|
||||
views.EpisodeListView.as_view(), name='episode-list'),
|
||||
path(_('programs/<slug:parent_slug>/articles/'),
|
||||
views.ArticleListView.as_view(), name='article-list'),
|
||||
path(_('programs/<slug:parent_slug>/publications/'),
|
||||
views.ProgramPageListView.as_view(), name='page-list'),
|
||||
|
||||
|
||||
]
|
||||
|
|
|
@ -5,5 +5,5 @@ from .base import BaseView
|
|||
from .episode import EpisodeDetailView, EpisodeListView, DiffusionListView
|
||||
from .log import LogListView
|
||||
from .page import PageDetailView, PageListView
|
||||
from .program import ProgramDetailView
|
||||
from .program import ProgramDetailView, ProgramPageListView
|
||||
|
||||
|
|
|
@ -49,6 +49,9 @@ class AdminSite(admin.AdminSite):
|
|||
path('tools/statistics/',
|
||||
self.admin_view(StatisticsView.as_view()),
|
||||
name='tools-stats'),
|
||||
path('tools/statistics/<date:date>/',
|
||||
self.admin_view(StatisticsView.as_view()),
|
||||
name='tools-stats'),
|
||||
]
|
||||
return urls
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ __all__ = ['ArticleDetailView', 'ArticleListView']
|
|||
|
||||
|
||||
class ArticleDetailView(PageDetailView):
|
||||
show_side_nav = True
|
||||
has_sidebar = True
|
||||
model = Article
|
||||
|
||||
def get_side_queryset(self):
|
||||
def get_sidebar_queryset(self):
|
||||
qs = Article.objects.select_related('cover') \
|
||||
.filter(is_static=False) \
|
||||
.order_by('-date')
|
||||
|
@ -27,9 +27,7 @@ class ArticleListView(ParentMixin, PageListView):
|
|||
template_name = 'aircox/article_list.html'
|
||||
show_headline = True
|
||||
is_static = False
|
||||
|
||||
parent_model = Program
|
||||
fk_parent = 'program'
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(is_static=self.is_static)
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.http import Http404
|
|||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.base import TemplateResponseMixin, ContextMixin
|
||||
|
||||
from ..models import Page
|
||||
from ..utils import Redirect
|
||||
|
||||
|
||||
|
@ -15,8 +16,10 @@ class BaseView(TemplateResponseMixin, ContextMixin):
|
|||
cover = None
|
||||
""" Page cover """
|
||||
|
||||
show_side_nav = False
|
||||
has_sidebar = True
|
||||
""" Show side navigation """
|
||||
has_filters = False
|
||||
""" Show filters nav """
|
||||
list_count = 5
|
||||
""" Item count for small lists displayed on page. """
|
||||
|
||||
|
@ -24,27 +27,29 @@ class BaseView(TemplateResponseMixin, ContextMixin):
|
|||
def station(self):
|
||||
return self.request.station
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().station(self.station)
|
||||
# def get_queryset(self):
|
||||
# return super().get_queryset().station(self.station)
|
||||
|
||||
def get_side_queryset(self):
|
||||
def get_sidebar_queryset(self):
|
||||
""" Return a queryset of items to render on the side nav. """
|
||||
return None
|
||||
return Page.objects.select_subclasses().published() \
|
||||
.order_by('-pub_date')
|
||||
|
||||
def get_context_data(self, side_items=None, **kwargs):
|
||||
def get_context_data(self, sidebar_items=None, **kwargs):
|
||||
kwargs.setdefault('station', self.station)
|
||||
kwargs.setdefault('cover', self.cover)
|
||||
kwargs.setdefault('has_filters', self.has_filters)
|
||||
|
||||
show_side_nav = kwargs.setdefault('show_side_nav', self.show_side_nav)
|
||||
if show_side_nav and side_items is None:
|
||||
side_items = self.get_side_queryset()
|
||||
side_items = None if side_items is None else \
|
||||
side_items[:self.list_count]
|
||||
has_sidebar = kwargs.setdefault('has_sidebar', self.has_sidebar)
|
||||
if has_sidebar and sidebar_items is None:
|
||||
sidebar_items = self.get_sidebar_queryset()
|
||||
sidebar_items = None if sidebar_items is None else \
|
||||
sidebar_items[:self.list_count]
|
||||
|
||||
if not 'audio_streams' in kwargs:
|
||||
streams = self.station.audio_streams
|
||||
streams = streams and streams.split('\n')
|
||||
kwargs['audio_streams'] = streams
|
||||
|
||||
return super().get_context_data(side_items=side_items, **kwargs)
|
||||
return super().get_context_data(sidebar_items=sidebar_items, **kwargs)
|
||||
|
||||
|
|
|
@ -35,18 +35,14 @@ class EpisodeListView(ParentMixin, PageListView):
|
|||
model = Episode
|
||||
item_template_name = 'aircox/episode_item.html'
|
||||
show_headline = True
|
||||
|
||||
parent_model = Program
|
||||
fk_parent = 'program'
|
||||
|
||||
|
||||
class DiffusionListView(GetDateMixin, BaseView, ListView):
|
||||
""" View for timetables """
|
||||
model = Diffusion
|
||||
|
||||
date = None
|
||||
start = None
|
||||
end = None
|
||||
has_filters = True
|
||||
redirect_date_url = 'diffusion-list'
|
||||
|
||||
def get_date(self):
|
||||
date = super().get_date()
|
||||
|
@ -56,19 +52,7 @@ class DiffusionListView(GetDateMixin, BaseView, ListView):
|
|||
return super().get_queryset().today(self.date).order_by('start')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
today = datetime.date.today()
|
||||
start = self.date - datetime.timedelta(days=self.date.weekday())
|
||||
dates = [
|
||||
(today, None),
|
||||
(today - datetime.timedelta(days=1), None),
|
||||
(today + datetime.timedelta(days=1), None),
|
||||
(today - datetime.timedelta(days=7), _('next week')),
|
||||
(today + datetime.timedelta(days=7), _('last week')),
|
||||
(None, None)
|
||||
] + [
|
||||
(date, date.strftime('%A %d'))
|
||||
for date in (start + datetime.timedelta(days=i)
|
||||
for i in range(0, 7)) if date != today
|
||||
]
|
||||
dates = [start + datetime.timedelta(days=i) for i in range(0, 7)]
|
||||
return super().get_context_data(date=self.date, dates=dates, **kwargs)
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ class LogListView(BaseView, LogListMixin, ListView):
|
|||
Return list of logs for the provided date (from `kwargs` or
|
||||
`request.GET`, defaults to today).
|
||||
"""
|
||||
redirect_date_url = 'log-list'
|
||||
has_filters = True
|
||||
|
||||
def get_date(self):
|
||||
date, today = super().get_date(), datetime.date.today()
|
||||
return today if date is None else min(date, today)
|
||||
|
@ -56,8 +59,7 @@ class LogListView(BaseView, LogListMixin, ListView):
|
|||
today = datetime.date.today()
|
||||
kwargs.update({
|
||||
'date': self.date,
|
||||
'dates': ((today - datetime.timedelta(days=i), None)
|
||||
for i in range(0, 7)),
|
||||
'dates': (today - datetime.timedelta(days=i) for i in range(0, 7)),
|
||||
'object_list': self.get_object_list(self.object_list),
|
||||
})
|
||||
return super().get_context_data(**kwargs)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from django.shortcuts import get_object_or_404
|
||||
import dateutil
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
|
||||
from ..utils import str_to_date
|
||||
|
||||
|
@ -12,13 +14,18 @@ class GetDateMixin:
|
|||
`kwargs['date']`
|
||||
"""
|
||||
date = None
|
||||
redirect_date_url = None
|
||||
|
||||
def get_date(self):
|
||||
if 'date' in self.request.GET:
|
||||
return str_to_date(self.request.GET['date'], '-')
|
||||
return self.kwargs['date'] if 'date' in self.kwargs else None
|
||||
date = self.request.GET.get('date')
|
||||
return str_to_date(date, '-') if date is not None else \
|
||||
self.kwargs['date'] if 'date' in self.kwargs else None
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
if self.redirect_date_url and self.request.GET.get('date'):
|
||||
return redirect(self.redirect_date_url,
|
||||
date=self.request.GET['date'].replace('-', '/'))
|
||||
|
||||
self.date = self.get_date()
|
||||
return super().get(*args, **kwargs)
|
||||
|
||||
|
@ -35,8 +42,6 @@ class ParentMixin:
|
|||
""" Url lookup argument """
|
||||
parent_field = 'slug'
|
||||
""" Parent field for url lookup """
|
||||
fk_parent = 'page'
|
||||
""" Page foreign key to the parent """
|
||||
parent = None
|
||||
""" Parent page object """
|
||||
|
||||
|
@ -54,8 +59,7 @@ class ParentMixin:
|
|||
|
||||
def get_queryset(self):
|
||||
if self.parent is not None:
|
||||
lookup = {self.fk_parent: self.parent}
|
||||
return super().get_queryset().filter(**lookup)
|
||||
return super().get_queryset().filter(parent=self.parent)
|
||||
return super().get_queryset()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import DetailView, ListView
|
||||
|
||||
|
@ -19,9 +18,11 @@ __all__ = ['PageDetailView', 'PageListView']
|
|||
class PageListView(BaseView, ListView):
|
||||
template_name = 'aircox/page_list.html'
|
||||
item_template_name = 'aircox/page_item.html'
|
||||
has_sidebar = True
|
||||
has_filters = True
|
||||
|
||||
paginate_by = 20
|
||||
show_headline = True
|
||||
show_side_nav = True
|
||||
categories = None
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
|
@ -36,7 +37,7 @@ class PageListView(BaseView, ListView):
|
|||
# (by id)
|
||||
if self.categories:
|
||||
qs = qs.filter(category__slug__in=self.categories)
|
||||
return qs.order_by('-date')
|
||||
return qs.order_by('-pub_date')
|
||||
|
||||
def get_categories_queryset(self):
|
||||
# TODO: use generic reverse field lookup
|
||||
|
@ -56,6 +57,7 @@ class PageListView(BaseView, ListView):
|
|||
class PageDetailView(BaseView, DetailView):
|
||||
""" Base view class for pages. """
|
||||
context_object_name = 'page'
|
||||
has_filters = False
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().select_related('cover', 'category')
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
from django.db.models import Q
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from aircox.models import Episode, Program
|
||||
from ..models import Episode, Program, Page
|
||||
from .mixins import ParentMixin
|
||||
from .page import PageDetailView, PageListView
|
||||
|
||||
|
||||
__all__ = ['ProgramPageDetailView', 'ProgramDetailView']
|
||||
__all__ = ['ProgramPageDetailView', 'ProgramDetailView', 'ProgramPageListView']
|
||||
|
||||
|
||||
class ProgramPageDetailView(PageDetailView):
|
||||
|
@ -13,24 +15,25 @@ class ProgramPageDetailView(PageDetailView):
|
|||
Base view class for a page that is displayed as a program's child page.
|
||||
"""
|
||||
program = None
|
||||
show_side_nav = True
|
||||
has_sidebar = True
|
||||
list_count = 5
|
||||
|
||||
def get_side_queryset(self):
|
||||
return self.program.episode_set.published().order_by('-date')
|
||||
def get_sidebar_queryset(self):
|
||||
return super().get_sidebar_queryset().filter(parent=self.object)
|
||||
|
||||
|
||||
class ProgramPageListView(ParentMixin, PageListView):
|
||||
model = Page
|
||||
parent_model = Program
|
||||
queryset = Page.objects.select_subclasses()
|
||||
|
||||
|
||||
class ProgramDetailView(ProgramPageDetailView):
|
||||
model = Program
|
||||
|
||||
def get_articles_queryset(self):
|
||||
return self.program.article_set.published().order_by('-date')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
self.program = kwargs.setdefault('program', self.object)
|
||||
if 'articles' not in kwargs:
|
||||
kwargs['articles'] = \
|
||||
self.get_articles_queryset()[:self.list_count]
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -24,3 +24,9 @@
|
|||
margin: 1em 0em;
|
||||
}
|
||||
|
||||
|
||||
ul.menu-list li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ export default {
|
|||
for(var tag of item.value.split(splitReg))
|
||||
counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;
|
||||
this.counts = counts;
|
||||
console.log('counts', this.counts)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ $body-background-color: $light;
|
|||
|
||||
@import "~bulma/bulma";
|
||||
|
||||
//-- helpers/modifiers
|
||||
.is-fullwidth { width: 100%; }
|
||||
.is-fixed-bottom {
|
||||
position: fixed;
|
||||
|
@ -18,6 +19,14 @@ $body-background-color: $light;
|
|||
background-color: transparent;
|
||||
}
|
||||
|
||||
.is-opacity-light {
|
||||
opacity: 0.7;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
//-- navbar
|
||||
.navbar + .container {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
@ -30,10 +39,44 @@ a.navbar-item.is-active {
|
|||
border-bottom: 1px grey solid;
|
||||
}
|
||||
|
||||
.navbar .navbar-dropdown {
|
||||
z-index: 2000;
|
||||
.navbar {
|
||||
.navbar-dropdown {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.navbar-split {
|
||||
margin: 0.2em 0em;
|
||||
margin-right: 1em;
|
||||
padding-right: 1em;
|
||||
border-right: 1px $grey-light solid;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0em;
|
||||
padding: 0em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-- filters
|
||||
.filters {
|
||||
margin: 1em 0em;
|
||||
background-color: transparent;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.title {
|
||||
padding-right: 2em;
|
||||
margin-right: 1em;
|
||||
border-right: 1px $grey-light solid;
|
||||
|
||||
font-size: $size-5;
|
||||
color: $text-light;
|
||||
font-weight: $weight-light;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
.navbar-brand img {
|
||||
min-height: 6em;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Django>=2.2.0
|
||||
djangorestframework>=3.9.4
|
||||
django-model-utils>=3.2.0
|
||||
|
||||
dateutils>=0.6.6
|
||||
watchdog>=0.8.3
|
||||
psutil>=5.0.1
|
||||
tzlocal>=1.4
|
||||
|
@ -12,7 +12,6 @@ django-filer>=1.5.0
|
|||
django-ckeditor>=5.7.1
|
||||
django-admin-sortable2>=0.7.2
|
||||
django-content-editor>=1.4.2
|
||||
|
||||
django-honeypot>=0.5.0
|
||||
|
||||
gunicorn>=19.6.0
|
||||
|
|
Loading…
Reference in New Issue
Block a user