# Imports
from django.conf import settings
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
import os
from superdjango.assets.library import JavaScript, StyleSheet
from superdjango.conf import SUPERDJANGO
from superdjango.views import BreadcrumbsMixin, MessageMixin
from .access import UIAccessMixin
# Exports
__all__ = (
"UIBaseMixin",
)
# Classes
[docs]class UIBaseMixin(UIAccessMixin, BreadcrumbsMixin, MessageMixin):
"""Base class for UI views (except AJAX)."""
active_page = None
"""The name of the active page that may be used to identify the current view within a menu."""
active_subpage = None
"""The name of the active subpage that may be used to identify the current view within a submenu."""
actions = None
"""An instance of :py:class:`superdjango.options.utils.Actions` containing the view-level actions for the current
view."""
# base_template = SUPERDJANGO.BASE_TEMPLATE
base_template = None
"""The base template used to render the view."""
raise_exception = settings.DEBUG
"""Indicates whether a processing exceptions should be raised or only logged."""
subtitle = None
"""The subtitle of the view page."""
template_name = None
"""The name of the template (which extends the ``base_template``) that is used to render the view. It omitted, an
attempt is made to determine the template name automatically. See ``get_template_names()``.
"""
template_name_suffix = None
"""The template suffix used to automatically determine the template name. See ``get_template_names()``."""
title = None
"""The title of the view page."""
ui = None
"""The ModelUI instance that generated the view."""
# actions_label = None
# permission_policy = None
# noinspection PyMethodMayBeStatic
[docs] def dispatch_not_found(self, message=None):
"""Dispatch a 404 (page not found) error. By default, this just raises an ``Http404``.
:param message: The 404 message.
"""
if message is None:
message = _("The requested page could not be located.")
raise Http404(message)
[docs] def get_base_template(self):
"""Get the name of the base template to use for rendering the view.
:rtype: str
"""
# Allow the UI to override settings.py
# noinspection PyUnresolvedReferences
base = self.ui.get_base_template(self.request, self.get_verb())
return base or SUPERDJANGO.BASE_TEMPLATE
[docs] def get_breadcrumbs(self):
"""Get breadcrumbs for the model view."""
crumbs = super().get_breadcrumbs()
# The "root" URL may be that of an app "above" this app.
label, root_url = self.ui.get_root_url()
if root_url is not None:
crumbs.add(label, root_url)
# If the index and root are different, also add the index of the current app.
index_url = self.ui.get_index_url()
if index_url != root_url:
crumbs.add(self.ui.get_verbose_name_plural(), index_url)
return crumbs
[docs] def get_context_data(self, *args, **kwargs):
# It's possible (as with django-formtools) that this method is defined on an extended view.
try:
# noinspection PyArgumentList
context = super().get_context_data(*args, **kwargs)
except AttributeError:
context = kwargs
if self.actions is not None:
context['actions_label'] = self.actions.label
context['active_page'] = self.active_page
context['active_subpage'] = self.active_subpage or "%s_%s" % (self.active_page, self.get_verb())
context['base_template'] = self.get_base_template()
context['breadcrumbs'] = self.get_breadcrumbs()
context['subtitle'] = self.get_subtitle()
context['title'] = self.get_title()
context['verbose_name'] = self.ui.get_verbose_name()
context['verbose_name_plural'] = self.ui.get_verbose_name_plural()
context['view'] = self
context['view_css'] = self.get_css()
context['view_js'] = self.get_js()
return context
# noinspection PyMethodMayBeStatic
[docs] def get_css(self):
"""Get the URLs or markup of any CSS to be included in the view.
:rtype: StyleSheet
"""
return StyleSheet()
# noinspection PyMethodMayBeStatic
[docs] def get_js(self):
"""Get the URLs or markup of any JavaScript to be included in the view.
:rtype: JavaScript
"""
return JavaScript()
[docs] def get_subtitle(self):
"""Get the page subtitle.
:rtype: str
"""
if self.subtitle is not None:
return self.subtitle
return ""
[docs] def get_template_name_suffix(self):
"""Get the suffix for the current view template.
:rtype: str
.. tip::
Extending classes should define the ``template_name_suffix``. The suffix should include an underscore for
separation. For example, the suffix for a view for creating a new record would be ``_add``.
The default behavior here is to return an empty string if ``template_name_suffix`` is not defined.
"""
if self.template_name_suffix is not None:
return self.template_name_suffix
return ""
[docs] def get_template_names(self):
"""Get the template names that may be used for rendering the response.
:rtype: list[str]
The possible names are generated like so:
1. If the child class defines a ``template_name``, this is always returned as the first element of the list.
2. This method first defines templates that may be defined by the local project in the form of
``{app_label}/{model_name_lower}{template_name_suffix}.html``.
3. Finally, the generic template is supplied for SuperDjango UI.
"""
templates = list()
# This will be the first template that is checked, which means it takes priority over any other possible
# template names.
if self.template_name is not None:
templates.append(self.template_name)
# The default template name is based on the suffix, which may supplied by the extending class or by view
# options. It takes second preference.
suffix = self.get_template_name_suffix()
if suffix is not None:
file_name = "%s%s.html" % (self.ui.meta.model_name, suffix)
templates.append(os.path.join(self.ui.meta.app_label, file_name))
# Include UI generic templates last.
file_name = "model%s.html" % suffix
templates.append(os.path.join("superdjango", "ui", file_name))
return templates
[docs] def get_title(self):
"""Get the page title.
:rtype: str
"""
if self.title is not None:
return self.title
return self.ui.get_verbose_name()
[docs] def get_verb(self):
"""Get the verb/action associated with the view.
:rtype: str
.. important::
Child classes must implement this method.
"""
raise NotImplementedError()