clean-up css; related publications; pagination
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -285,7 +285,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
||||
\************************************************************************************************************************************************************************************************************************************************************************/
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm-bundler.js\");\n\nconst _hoisted_1 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon mr-3\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"i\", {\n class: \"fa fa-play\"\n})], -1 /* HOISTED */);\nconst _hoisted_2 = {\n class: \"button-group actions\"\n};\nconst _hoisted_3 = [\"href\"];\nconst _hoisted_4 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon is-small\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"i\", {\n class: \"fa fa-external-link\"\n})], -1 /* HOISTED */);\nconst _hoisted_5 = [_hoisted_4];\nconst _hoisted_6 = [\"href\"];\nconst _hoisted_7 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon is-small\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"fa fa-download\"\n})], -1 /* HOISTED */);\nconst _hoisted_8 = [_hoisted_7];\nconst _hoisted_9 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon is-small\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"fa fa-star\"\n})], -1 /* HOISTED */);\nconst _hoisted_10 = [_hoisted_9];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['a-sound-item m-0 button-group', $options.playing && 'playing' || ''])\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"title\", {\n player: $props.player,\n item: $options.item,\n loaded: $options.loaded\n }, () => [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['title is-flex-grow-1', $options.playing && 'blink' || '']),\n onClick: _cache[0] || (_cache[0] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => _ctx.$emit('togglePlay'), [\"stop\"]))\n }, [_hoisted_1, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(\" \" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.name || $options.item.name), 1 /* TEXT */)], 2 /* CLASS */)]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_2, [$options.hasAction('page') ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"a\", {\n key: 0,\n class: \"button\",\n href: $options.item.data.page_url\n }, _hoisted_5, 8 /* PROPS */, _hoisted_3)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), $options.item.data.is_downloadable ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"a\", {\n key: 1,\n class: \"button\",\n href: $options.item.data.url,\n target: \"_blank\"\n }, _hoisted_8, 8 /* PROPS */, _hoisted_6)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), $props.player && $props.player.sets.pin != _ctx.$parent.set ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"button\", {\n key: 2,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['button', $options.pinned ? 'selected' : 'not-selected']),\n onClick: _cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => $props.player.togglePin($options.item), [\"stop\"]))\n }, _hoisted_10, 2 /* CLASS */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"actions\", {\n player: $props.player,\n item: $options.item,\n loaded: $options.loaded\n })]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"extra-right\", {\n player: $props.player,\n item: $options.item,\n loaded: $options.loaded\n })], 2 /* CLASS */);\n}\n\n//# sourceURL=webpack://aircox-assets/./src/components/ASoundItem.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use%5B0%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B3%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D");
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm-bundler.js\");\n\nconst _hoisted_1 = {\n class: \"button-group actions\"\n};\nconst _hoisted_2 = [\"href\"];\nconst _hoisted_3 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon is-small\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"i\", {\n class: \"fa fa-external-link\"\n})], -1 /* HOISTED */);\nconst _hoisted_4 = [_hoisted_3];\nconst _hoisted_5 = [\"href\"];\nconst _hoisted_6 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon is-small\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"fa fa-download\"\n})], -1 /* HOISTED */);\nconst _hoisted_7 = [_hoisted_6];\nconst _hoisted_8 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"icon is-small\"\n}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: \"fa fa-star\"\n})], -1 /* HOISTED */);\nconst _hoisted_9 = [_hoisted_8];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['a-sound-item m-0 button-group', $options.playing && 'playing' || ''])\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"title\", {\n player: $props.player,\n item: $options.item,\n loaded: $options.loaded\n }, () => [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['title is-flex-grow-1 align-left', $options.playing && 'blink' || '']),\n onClick: _cache[0] || (_cache[0] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => _ctx.$emit('togglePlay'), [\"stop\"]))\n }, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.name || $options.item.name), 3 /* TEXT, CLASS */)]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_1, [$options.hasAction('page') ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"a\", {\n key: 0,\n class: \"button action\",\n href: $options.item.data.page_url\n }, _hoisted_4, 8 /* PROPS */, _hoisted_2)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), $options.item.data.is_downloadable ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"a\", {\n key: 1,\n class: \"button action\",\n href: $options.item.data.url,\n target: \"_blank\"\n }, _hoisted_7, 8 /* PROPS */, _hoisted_5)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), $props.player && $props.player.sets.pin != _ctx.$parent.set ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"button\", {\n key: 2,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['button action', $options.pinned ? 'selected' : 'not-selected']),\n onClick: _cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => $props.player.togglePin($options.item), [\"stop\"]))\n }, _hoisted_9, 2 /* CLASS */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"actions\", {\n player: $props.player,\n item: $options.item,\n loaded: $options.loaded\n })]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"extra-right\", {\n player: $props.player,\n item: $options.item,\n loaded: $options.loaded\n })], 2 /* CLASS */);\n}\n\n//# sourceURL=webpack://aircox-assets/./src/components/ASoundItem.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use%5B0%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B3%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D");
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
@ -48,41 +48,30 @@
|
||||
<hr/>
|
||||
{% update_query request.GET.copy page=None as GET %}
|
||||
{% with GET.urlencode as GET %}
|
||||
<nav class="pagination is-centered" role="pagination" aria-label="{% translate "pagination" %}">
|
||||
<nav class="nav-urls is-centered" role="pagination" aria-label="{% translate "pagination" %}">
|
||||
{% block pagination %}
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?{{ GET }}&page={{ page_obj.previous_page_number }}" class="pagination-previous">
|
||||
{% else %}
|
||||
<a class="pagination-previous" disabled>
|
||||
{% endif %}
|
||||
<a href="?{{ GET }}&page={{ page_obj.previous_page_number }}" class="left button">
|
||||
{% comment %}Translators: Bottom of the list, "previous page"{% endcomment %}
|
||||
{% translate "Previous" %}</a>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?{{ GET }}&page={{ page_obj.next_page_number }}" class="pagination-next">
|
||||
{% else %}
|
||||
<a class="pagination-next" disabled>
|
||||
{% endif %}
|
||||
{% comment %}Translators: Bottom of the list, "Nextpage"{% endcomment %}
|
||||
{% translate "Next" %}</a>
|
||||
|
||||
<ul class="pagination-list">
|
||||
<ul class="urls">
|
||||
{% for i in paginator.page_range %}
|
||||
<li>
|
||||
{% comment %}
|
||||
<form action="?{{ GET }}">
|
||||
{% for get in GET %}
|
||||
<input type="hidden" name="{{ get.0 }}" value="{{ get.1 }}" />
|
||||
{% endfor %}
|
||||
<input type="number" name="page" value="{{ page_obj.number }}" />
|
||||
</form>
|
||||
{% endcomment %}
|
||||
<a class="pagination-link {% if page_obj.number == i %}is-current{% endif %}"
|
||||
<a class="button {% if page_obj.number == i %}active{% endif %}"
|
||||
href="?{{ GET }}&page={{ i }}">{{ i }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?{{ GET }}&page={{ page_obj.next_page_number }}" class="right button">
|
||||
{% comment %}Translators: Bottom of the list, "Nextpage"{% endcomment %}
|
||||
{% translate "Next" %}</a>
|
||||
{% endif %}
|
||||
|
||||
</nav>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
@ -39,7 +39,7 @@
|
||||
{% include "./widgets/log.html" with widget="item" %}
|
||||
{% endfor %}
|
||||
|
||||
<nav class="list-urls">
|
||||
<nav class="nav-urls">
|
||||
<a href="{% url "diffusion-list" %}"
|
||||
aria-label="{% translate "Show all program's for today" %}">
|
||||
{% translate "Today" %}
|
||||
@ -58,7 +58,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<nav class="list-urls">
|
||||
<nav class="nav-urls">
|
||||
<a href="{% url "page-list" %}"
|
||||
aria-label="{% translate "Show all publications" %}">
|
||||
{% translate "All publications" %}
|
||||
|
@ -6,6 +6,8 @@ Base template used to display a Page
|
||||
Context:
|
||||
- page: page
|
||||
- parent: parent page
|
||||
- related_objects: list of object to display as related publications
|
||||
- related_url: url to the full list of related_objects
|
||||
{% endcomment %}
|
||||
|
||||
{% block header_crumbs %}
|
||||
@ -31,6 +33,29 @@ Context:
|
||||
{% block main %}
|
||||
{{ block.super }}
|
||||
|
||||
{% block related %}
|
||||
{% if related_objects %}
|
||||
<section class="container">
|
||||
{% with models=object|verbose_name:True %}
|
||||
<h3 class="title is-3">{% blocktranslate %}Related {{models}}{% endblocktranslate %}</h3>
|
||||
{% endwith %}
|
||||
|
||||
<section class="card-grid">
|
||||
{% for object in related_objects %}
|
||||
{% page_widget "card" object %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
{% if related_url %}
|
||||
<nav class="nav-urls">
|
||||
<a href="{{ related_url }}">
|
||||
{% translate "See more" %}
|
||||
</a>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block comments %}
|
||||
{% if comments %}
|
||||
<section class="container">
|
||||
@ -46,8 +71,8 @@ Context:
|
||||
|
||||
{% if comment_form %}
|
||||
<section class="container">
|
||||
<h2 class="title">{% translate "Post a comment" %}</h2>
|
||||
<form method="POST">
|
||||
<h2 class="title">{% translate "Post a comment" %}</h2>
|
||||
{% csrf_token %}
|
||||
{% render_honeypot_field "website" %}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
{% block secondary-nav %}
|
||||
<form class="nav secondary">
|
||||
{% for id, title in view.categories.items %}
|
||||
<a class="nav-item{% if category_id == id %} active{% endif %}"
|
||||
<a class="nav-item{% if category_id == id or parent and parent.category_id == id %} active{% endif %}"
|
||||
href="?category__id={{ id }}">{{ title }}</a>
|
||||
{% endfor %}
|
||||
</form>
|
||||
|
@ -16,9 +16,9 @@
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<nav class="list-urls">
|
||||
<nav class="nav-urls">
|
||||
<a href="{% url "episode-list" parent_slug=program.slug %}">
|
||||
{% translate "All episodes" %}
|
||||
{% translate "See more" %}
|
||||
</a>
|
||||
</nav>
|
||||
</section>
|
||||
@ -35,10 +35,10 @@
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<nav class="list-urls">
|
||||
<nav class="nav-urls">
|
||||
<a href="{% url "article-list" parent_slug=program.slug %}"
|
||||
aria-label="{% translate "Show all program's articles" %}">
|
||||
{% translate "All articles" %}
|
||||
{% translate "See more" %}
|
||||
</a>
|
||||
</nav>
|
||||
</section>
|
||||
|
@ -40,7 +40,7 @@ Context variables:
|
||||
|
||||
<div class="actions">
|
||||
{% block actions %}
|
||||
<a class="button btn-hg float-right" href="{{ object.get_absolute_url|escape }}">
|
||||
<a class="button float-right" href="{{ object.get_absolute_url|escape }}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-external-link"></i>
|
||||
</span>
|
||||
|
@ -90,7 +90,10 @@ def do_nav_items(context, menu, **kwargs):
|
||||
|
||||
@register.simple_tag(name="update_query")
|
||||
def do_update_query(obj, **kwargs):
|
||||
"""Replace provided querydict's values with **kwargs."""
|
||||
"""Replace provided querydict's values with **kwargs.
|
||||
|
||||
Values set to ``None`` will be dropped.
|
||||
"""
|
||||
for k, v in kwargs.items():
|
||||
if v is not None:
|
||||
obj[k] = list(v) if hasattr(v, "__iter__") else [v]
|
||||
@ -103,4 +106,6 @@ def do_update_query(obj, **kwargs):
|
||||
def do_verbose_name(obj, plural=False):
|
||||
"""Return model's verbose name (singular or plural) or `obj` if it is a
|
||||
string (can act for default values)."""
|
||||
return obj if isinstance(obj, str) else obj._meta.verbose_name_plural if plural else obj._meta.verbose_name
|
||||
if isinstance(obj, str):
|
||||
return obj
|
||||
return obj._meta.verbose_name_plural if plural else obj._meta.verbose_name
|
||||
|
@ -1,3 +1,5 @@
|
||||
from django.shortcuts import reverse
|
||||
|
||||
from ..filters import EpisodeFilters
|
||||
from ..models import Episode, Program, StaticPage
|
||||
from .page import PageListView
|
||||
@ -17,6 +19,14 @@ class EpisodeDetailView(ProgramPageDetailView):
|
||||
kwargs["tracks"] = self.object.track_set.order_by("position")
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_related_queryset(self):
|
||||
return (
|
||||
self.get_queryset().parent(self.object.parent).exclude(pk=self.object.pk).published().order_by("-pub_date")
|
||||
)
|
||||
|
||||
def get_related_url(self):
|
||||
return reverse("episode-list", kwargs={"parent_slug": self.object.parent.slug})
|
||||
|
||||
|
||||
class EpisodeListView(PageListView):
|
||||
model = Episode
|
||||
|
@ -119,7 +119,12 @@ class PageListView(FiltersMixin, BasePageListView):
|
||||
if cat_id:
|
||||
cat_id = int(cat_id)
|
||||
kwargs["category_id"] = cat_id
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
if context.get("parent") and not cat_id:
|
||||
kwargs["category_id"] = context["parent"].category_id
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class PageDetailView(BasePageDetailView):
|
||||
@ -128,6 +133,16 @@ class PageDetailView(BasePageDetailView):
|
||||
template_name = None
|
||||
context_object_name = "page"
|
||||
|
||||
related_count = 3
|
||||
|
||||
def get_related_queryset(self):
|
||||
"""Return a queryset of related pages or None."""
|
||||
return None
|
||||
|
||||
def get_related_url(self):
|
||||
"""Return an url to the list of related pages."""
|
||||
return None
|
||||
|
||||
def get_template_names(self):
|
||||
return super().get_template_names() + ["aircox/page_detail.html"]
|
||||
|
||||
@ -138,8 +153,16 @@ class PageDetailView(BasePageDetailView):
|
||||
if self.object.allow_comments and "comment_form" not in kwargs:
|
||||
kwargs["comment_form"] = CommentForm()
|
||||
kwargs["comments"] = Comment.objects.filter(page=self.object).order_by("-date")
|
||||
|
||||
if self.object.parent_subclass:
|
||||
kwargs["parent"] = self.object.parent_subclass
|
||||
|
||||
if "related_objects" not in kwargs:
|
||||
related = self.get_related_queryset()
|
||||
if related:
|
||||
related = related[: self.related_count]
|
||||
kwargs["related_objects"] = related
|
||||
kwargs["related_url"] = self.get_related_url()
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
@classmethod
|
||||
|
@ -1,3 +1,5 @@
|
||||
import random
|
||||
|
||||
from django.urls import reverse
|
||||
|
||||
from ..models import Article, Page, Program, StaticPage, Episode
|
||||
@ -23,6 +25,19 @@ class BaseProgramMixin:
|
||||
class ProgramDetailView(BaseProgramMixin, PageDetailView):
|
||||
model = Program
|
||||
|
||||
def get_related_queryset(self):
|
||||
queryset = (
|
||||
self.get_queryset()
|
||||
.filter(category_id=self.object.category_id)
|
||||
.exclude(pk=self.object.pk)
|
||||
.published()
|
||||
.order_by("-pub_date")[:50]
|
||||
)
|
||||
return random.sample(list(queryset), self.related_count)
|
||||
|
||||
def get_related_url(self):
|
||||
return reverse("program-list") + f"?category__id={self.object.category_id}"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
episodes = Episode.objects.program(self.object).published().order_by("-pub_date")
|
||||
articles = Article.objects.parent(self.object).published().order_by("-pub_date")
|
||||
|
Reference in New Issue
Block a user