Source code for djangocms_stories.views

import os.path

from django.contrib.auth import get_user_model
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.timezone import now
from django.utils.translation import get_language
from django.views.generic import DetailView, ListView
from parler.views import TranslatableSlugMixin, ViewUrlMixin

from cms.utils import get_current_site

from .cms_appconfig import get_app_instance
from .models import PostCategory, PostContent
from .settings import get_setting
from .utils import site_compatibility_decorator


User = get_user_model()

get_current_site = site_compatibility_decorator(get_current_site)


class StoriesConfigMixin:
    def dispatch(self, request, *args, **kwargs):
        """Detect current namespace and config instance. Add both to the view object and
        make namespace avilable to the request."""

        self.namespace, self.config = get_app_instance(request)
        request.current_app = self.namespace
        return super().dispatch(request, *args, **kwargs)

    def render_to_response(self, context, **response_kwargs):
        """Make current app available to the template"""
        if "current_app" in response_kwargs:  # pragma: no cover
            response_kwargs["current_app"] = self.namespace
        return super().render_to_response(context, **response_kwargs)


[docs] class PostDetailView(StoriesConfigMixin, DetailView): model = PostContent context_object_name = "post_content" base_template_name = "post_detail.html" slug_field = "slug" view_url_name = "djangocms_stories:post-detail" instant_article = False
[docs] def get(self, request, *args, **kwargs): """Make toolbar object's apphook config available""" if hasattr(request, "toolbar") and self.config is None: obj = request.toolbar.get_object() if isinstance(obj, PostContent): self.config = getattr(request.toolbar.get_object().post, "app_config", None) else: self.config = None return super().get(request, *args, **kwargs)
[docs] def get_template_names(self): if self.instant_article: template_path = (self.config and self.config.template_prefix) or "djangocms_stories" return [os.path.join(template_path, "post_instant_article.html")] else: template_path = (self.config and self.config.template_prefix) or "djangocms_stories" return [os.path.join(template_path, self.base_template_name)]
[docs] def get_object(self): obj = super().get_object() try: # Add to toolbar if not in endpoint self.request.toolbar.set_object(obj) except AttributeError: pass setattr(self.request, get_setting("CURRENT_POST_IDENTIFIER"), obj) return obj
[docs] def get_context_data(self, **kwargs): setattr(self.request, get_setting("CURRENT_NAMESPACE"), self.config) context = super().get_context_data(**kwargs) context["post"] = context["post_content"] # Temporary to allow for easier transition from v3 to v4 context["meta"] = self.get_object().as_meta() context["instant_article"] = self.instant_article context["use_placeholder"] = get_setting("USE_PLACEHOLDER") return context
class ToolbarDetailView(PostDetailView): """Mimics DetailView but takes content object from render function""" def get_object(self): content_object = self.args[0] self.request.current_app = content_object.post.app_config.namespace setattr(self.request, get_setting("CURRENT_NAMESPACE"), content_object.post.app_config) return content_object class BaseConfigListViewMixin(StoriesConfigMixin): def optimize(self, qs): """ Apply select_related / prefetch_related to optimize the view queries :param qs: queryset to optimize :return: optimized queryset """ return qs.select_related("post__app_config").prefetch_related( "post__categories", "post__categories__translations", "post__categories__app_config" ) def get_view_url(self): if not self.view_url_name: raise ImproperlyConfigured(f"Missing `view_url_name` attribute on {self.__class__.__name__}") url = reverse(self.view_url_name, args=self.args, kwargs=self.kwargs, current_app=self.namespace) return self.request.build_absolute_uri(url) def get_queryset(self): language = get_language() if hasattr(self.request, "toolbar") and ( self.request.toolbar.edit_mode_active or self.request.toolbar.preview_mode_active ): queryset = self.model.admin_manager.latest_content() else: queryset = self.model.objects.all() queryset = queryset.filter(language=language, post__app_config__namespace=self.namespace) setattr(self.request, get_setting("CURRENT_NAMESPACE"), self.config) site = get_current_site(self.request) return self.optimize(queryset.on_site(site)) def get_template_names(self): template_path = (self.config and self.config.template_prefix) or "djangocms_stories" return os.path.join(template_path, self.base_template_name) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["TRUNCWORDS_COUNT"] = get_setting("POSTS_LIST_TRUNCWORDS_COUNT") return context def get_paginate_by(self, queryset): return (self.config and self.config.paginate_by) or get_setting("PAGINATION")
[docs] class PostListView(BaseConfigListViewMixin, ListView): model = PostContent base_template_name = "post_list.html" view_url_name = "djangocms_stories:posts-latest"
class CategoryListView(StoriesConfigMixin, ViewUrlMixin, TranslatableSlugMixin, ListView): model = PostCategory context_object_name = "category_list" base_template_name = "category_list.html" view_url_name = "djangocms_stories:categories-all" def get_queryset(self): language = get_language() queryset = self.model._default_manager.filter(app_config__namespace=self.namespace).active_translations( language_code=language ) queryset = queryset.filter(parent__isnull=True, priority__isnull=False) # Only top-level categories setattr(self.request, get_setting("CURRENT_NAMESPACE"), self.config) return queryset def get_template_names(self): template_path = (self.config and self.config.template_prefix) or "djangocms_stories" return os.path.join(template_path, self.base_template_name)
[docs] class PostArchiveView(BaseConfigListViewMixin, ListView): model = PostContent context_object_name = "postcontent_list" base_template_name = "post_list.html" date_field = "date_published" allow_empty = True allow_future = True view_url_name = "djangocms_stories:posts-archive"
[docs] def get_queryset(self): qs = super().get_queryset() if "month" in self.kwargs: qs = qs.filter(**{"post__%s__month" % self.date_field: self.kwargs["month"]}) if "year" in self.kwargs: qs = qs.filter(**{"post__%s__year" % self.date_field: self.kwargs["year"]}) return self.optimize(qs)
[docs] def get_context_data(self, **kwargs): kwargs["month"] = int(self.kwargs.get("month")) if "month" in self.kwargs else None kwargs["year"] = int(self.kwargs.get("year")) if "year" in self.kwargs else None if kwargs["year"]: kwargs["archive_date"] = now().replace(kwargs["year"], kwargs["month"] or 1, 1) context = super().get_context_data(**kwargs) return context
[docs] class TaggedListView(BaseConfigListViewMixin, ListView): model = PostContent context_object_name = "postcontent_list" base_template_name = "post_list.html" view_url_name = "djangocms_stories:posts-tagged"
[docs] def get_queryset(self): qs = super().get_queryset() return self.optimize(qs.filter(post__tags__slug=self.kwargs["tag"]))
[docs] def get_context_data(self, **kwargs): kwargs["tagged_entries"] = self.kwargs.get("tag") if "tag" in self.kwargs else None context = super().get_context_data(**kwargs) return context
[docs] class AuthorEntriesView(BaseConfigListViewMixin, ListView): model = PostContent context_object_name = "postcontent_list" base_template_name = "post_list.html" view_url_name = "djangocms_stories:posts-author"
[docs] def get_queryset(self): qs = super().get_queryset() if "username" in self.kwargs: qs = qs.filter(**{"post__author__%s" % User.USERNAME_FIELD: self.kwargs["username"]}) return self.optimize(qs)
[docs] def get_context_data(self, **kwargs): kwargs["author"] = get_object_or_404(User, **{User.USERNAME_FIELD: self.kwargs.get("username")}) context = super().get_context_data(**kwargs) return context
[docs] class CategoryEntriesView(BaseConfigListViewMixin, ListView): _category = None model = PostContent context_object_name = "postcontent_list" base_template_name = "post_list.html" view_url_name = "djangocms_stories:posts-category" @property def category(self): if not self._category: try: self._category = PostCategory.objects.active_translations( get_language(), slug=self.kwargs["category"] ).get() except PostCategory.DoesNotExist: raise Http404 return self._category
[docs] def get_queryset(self): qs = super().get_queryset() if "category" in self.kwargs: qs = qs.filter(post__categories=self.category.pk) return self.optimize(qs)
[docs] def get_context_data(self, **kwargs): kwargs["category"] = self.category context = super().get_context_data(**kwargs) context["meta"] = self.category.as_meta() return context