Source code for lotus.views.mixins
from django.conf import settings
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from ..exceptions import Http500
from ..lookups import LookupBuilder
from ..utils.language import get_language_code
[docs]
class NoOperationBreadcrumMixin:
"""
A dummy and empty mixin to use when 'view_breadcrumbs' is not available.
"""
pass
[docs]
class PreviewModeMixin:
"""
A mixin to contain the logic for preview mode and add a context variable
``preview_mode``.
Preview mode is only allowed for staff users which use URL with a specific argument
as defined in setting ``LOTUS_PREVIEW_KEYWORD``.
A staff user is only allowed for preview mode if its session have the right item set
to ``True`` exactly.
The preview mode is essentially used to not filter queryset with publication
criterias.
"""
[docs]
def allowed_preview_mode(self, request):
"""
Return if preview mode is enabled or not.
"""
if not self.request.user.is_staff:
return False
return self.request.session.get(settings.LOTUS_PREVIEW_KEYWORD, None) is True
[docs]
def get_context_data(self, **kwargs):
"""
Expose the preview mode state to template.
"""
context = super().get_context_data(**kwargs)
context[settings.LOTUS_PREVIEW_VARNAME] = self.allowed_preview_mode(
self.request
)
return context
[docs]
class ArticleFilterMixin(LookupBuilder):
"""
A mixin to share Article filtering.
.. TODO::
Rewrite docstrings since allowed_preview_mode deps is not required
anymore, only optional.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# TODO: Documentate this new attribute and why it exists here instead of
# previously in method build/apply lookup
self.target_date = timezone.now()
def is_for_authenticated_user(self):
if not hasattr(self, "request"):
return False
return self.request.user.is_authenticated
[docs]
def build_article_lookups(self, language=None, prefix=None):
"""
Build complex lookups to apply common publication criterias.
Also set a ``self.target_date`` attribute to store the date checked
against as a reference for further usage (like in ``get_context_data``).
Depends on ``allowed_preview_mode`` method as implemented in
``PreviewModeMixin`` (that manage preview mode) and the queryset must be for a
model with a manager which implement ``get_for_lang`` and ``get_published``
methods.
Keyword Arguments:
language (string): Language code to filter on.
Returns:
tuple: The lookups to give to a queryset filter.
"""
lookups = []
prefix = prefix or ""
# Define target_date attribute if it does not exists yet
if not hasattr(self, "target_date"):
self.target_date = timezone.now()
# Check for enabled preview mode
if (
language and
hasattr(self, "allowed_preview_mode") and
self.allowed_preview_mode(self.request)
):
lookups.extend(
self.build_language_conditions(language, prefix=prefix)
)
# Default request instead
else:
lookups.extend(
self.build_publication_conditions(
target_date=None,
language=language,
private=None if self.is_for_authenticated_user() else False,
prefix=prefix,
)
)
return tuple(lookups)
[docs]
def apply_article_lookups(self, queryset, language=None):
"""
Apply publication and language lookups to given queryset.
This will set a ``self.target_date`` attribute to store the date checked
against as a reference for further usage (like in ``get_context_data``).
The queryset must be for a model with a manager which implement
``get_for_lang`` and ``get_published`` methods. This support also
``allowed_preview_mode`` method as implemented in ``PreviewModeMixin``
(that manage preview mode) if it is available.
Arguments:
queryset (django.db.models.QuerySet): Base queryset to start on.
Keyword Arguments:
language (string): Language code to filter on.
Returns:
django.db.models.QuerySet: Improved queryset with required filtering
lookups.
"""
# Define target_date attribute if it does not exists yet
if not hasattr(self, "target_date"):
self.target_date = timezone.now()
# Check for enabled preview mode which allows to ignore publication rules, only
# care about language
if (
hasattr(self, "allowed_preview_mode") and
self.allowed_preview_mode(self.request)
) and language:
queryset = queryset.get_for_lang(language=language)
# Default request instead
else:
queryset = queryset.get_published(
target_date=self.target_date,
language=language,
private=None if self.is_for_authenticated_user() else False,
)
return queryset
[docs]
class LanguageMixin:
"""
A mixin to provide very common logic related to language.
"""
[docs]
def get_language_code(self):
"""
Shortand to ``get_language_code`` function that already give the request object.
.. Warning::
This should not be used in view code before request attribute has been set.
Returns:
string: Language code retrieved either from request object or settings.
"""
return get_language_code(self.request)
[docs]
class LotusContextStage:
"""
Mixin to inject Lotus stage into view context.
Lotus stage is commonly used for Lotus navigation, it just indicates where a view
is located from main Lotus content type views (Article, Author, Category, ..).
Views which inherits from this mixin should set view attribute ``lotus_stage`` to
a main content type in lowercase like ``articles``, ``authors``, ``category``.
The default stage value is ``None``.
Finally, the Lotus stage is just an helper for basic navigation like in a menu to
highlight corresponding item. There is no code which use it so it can be ignored
from custom Lotus implementation.
"""
lotus_stage = None
def get_lotus_stage(self):
return self.lotus_stage
[docs]
def get_context_data(self, **kwargs):
"""
Expose the date "now" used for publication filter.
"""
context = super().get_context_data(**kwargs)
context["lotus_stage"] = self.get_lotus_stage()
return context
[docs]
class ArticleFilterAbstractView(LotusContextStage, ArticleFilterMixin,
PreviewModeMixin, LanguageMixin):
"""
Abstract class which gather all the classes needed to implement filtering on
criterias.
"""
[docs]
def get_context_data(self, **kwargs):
"""
Expose the date "now" used for publication filter and the article filtering.
function
"""
context = super().get_context_data(**kwargs)
context["article_filter_func"] = getattr(self, "apply_article_lookups")
context["lotus_now"] = getattr(self, "target_date")
return context
[docs]
class TemplateFromObjectMixin:
"""
A mixin to get the template to render from the object attribute ``template``.
It is intended to override the template mechanism from ``TemplateResponseMixin`` and
for a view which have an attribute ``object`` where to find the attribute
``template``.
"""
[docs]
def get_template_names(self):
"""
Overrides the original method to get the template name from the object.
Returns:
list: List of template name as expected by the Django mechanism but the
list will always have an unique item.
"""
if not hasattr(self, "object"):
raise Http500(
_("TemplateFromObjectMixin usage requires an attribute 'object'.")
)
return [self.object.template]