Source code for djangocms_restapi.menu.views
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import re
from django.template import Template
from django.template.context import Context
from rest_framework.request import clone_request
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from cms.middleware.page import CurrentPageMiddleware
from .serializers import NavigationNodeSerializer
class CurrentPageAPIContextMixin(CurrentPageMiddleware):
"""
Returns a Context object with a clone of the HttpRequest.
The request clone is ran through the ``CurrentPageMiddleware``
before returned.
"""
def __init__(self, *args, **kwargs):
super(CurrentPageAPIContextMixin, self).__init__(*args, **kwargs)
self.context = Context()
def get_context(self, request):
request = clone_request(request, request.method)
if "current_page" in request.GET:
# Runs through regex in order to clean up potential double quoted strings.
request.path = request.path_info = re.sub(r'^"|"$', '', request.GET["current_page"])
self.process_request(request)
self.context["request"] = request
return self.context
[docs]class ShowMenuViewSet(CurrentPageAPIContextMixin, GenericViewSet):
"""
API Endpoint which calls the ``{% show_menu %}`` tag and returns
a serialized list of ``NavigationNodes``.
The following query parameters will be used to construct the argument
list which will be passed to the template tag.
===================== ================================================================
Query parameters Description
===================== ================================================================
start_level (int): Specify from which level the navigation should be rendered.
end_level (int): Specify from which level the navigation should stop rendering.
extra_inactive (int): Specifies how many levels of navigation should be displayed \n
if a node is not a direct ancestor or descendant of the current \n
active node.
extra_active (int): Specifies how many levels of descendants of the currently \n
active node that should be displayed.
namespace (str): The namespace of the menu. If blank, all namespaces will be used.
current_page (str): URL for the page that should be considered the `current_page` \n
when rendering the context.
===================== ================================================================
"""
serializer_class = NavigationNodeSerializer
def render_context(self, context):
"""
Render and return the context
"""
args = ("{start_level} {end_level} {extra_inactive} "
"{extra_active} {template} {namespace}").format(
start_level=self.request.GET.get("start_level", 0),
end_level=self.request.GET.get("end_level", 100),
extra_inactive=self.request.GET.get("extra_inactive", 0),
extra_active=self.request.GET.get("extra_active", 1000),
template='"menu/menu.html"',
namespace='"%s"' % self.request.GET.get("namespace", ""),
)
template = Template(
"".join(("{% load menu_tags %}{% show_menu ", args, " %}"))
)
template.render(context)
return context
def get_queryset(self):
"""
Retrieve the list of menu items for the menu.
"""
context = self.render_context(self.get_context(self.request))
return context["children"]
def list(self, request, *args, **kwargs):
"""
Serialize and return the queryset. The menu list
are never paginated.
"""
queryset = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
[docs]class ShowMenuBelowIdViewSet(ShowMenuViewSet):
"""
API Endpoint which calls the ``{% show_menu_below_id %}`` tag and returns
a serialized list of ``NavigationNodes``.
The following query parameters will be used to construct the argument
list which will be passed to the template tag.
===================== ================================================================
Query parameters Description
===================== ================================================================
root_id (str): Specify the ID of the root node.
start_level (int): Specify from which level the navigation should be rendered.
end_level (int): Specify from which level the navigation should stop rendering.
extra_inactive (int): Specifies how many levels of navigation should be displayed \n
if a node is not a direct ancestor or descendant of the current \n
active node.
extra_active (int): Specifies how many levels of descendants of the currently active \n
node that should be displayed.
namespace (str): The namespace of the menu. If blank, all namespaces will be used.
current_page (str): URL for the page that should be considered the `current_page` \n
when rendering the context.
===================== ================================================================
"""
def render_context(self, context):
"""
Render and return the context
"""
args = ("{root_id} {start_level} {end_level} {extra_inactive} "
"{extra_active} {template} {namespace}").format(
root_id='"%s"' % self.request.GET.get("root_id", ""),
start_level=self.request.GET.get("start_level", 0),
end_level=self.request.GET.get("end_level", 100),
extra_inactive=self.request.GET.get("extra_inactive", 0),
extra_active=self.request.GET.get("extra_active", 1000),
template='"menu/menu.html"',
namespace='"%s"' % self.request.GET.get("namespace", "")
)
template = Template(
"".join(("{% load menu_tags %}{% show_menu_below_id ", args, " %}"))
)
template.render(context)
return context
[docs]class ShowSubMenuViewSet(ShowMenuViewSet):
"""
API Endpoint which calls the ``{% show_sub_menu %}`` tag and returns
a serialized list of ``NavigationNodes``.
The following query parameters will be used to construct the argument
list which will be passed to the template tag.
===================== ================================================================
Query parameters Description
===================== ================================================================
levels (int): Specify how many levels deep the sub menu should be rendered.
root_level (int): Specifies at what level (if any) the sub menu should have its root.
nephews (int): Specifies how many levels of nephews (children of siblings) that \n
should be displayed.
current_page (str): URL for the page that should be considered the `current_page` \n
when rendering the context.
===================== ================================================================
"""
def render_context(self, context):
"""
Constructs the template tag arguments and render it.
Returns the context.
"""
args = "{levels} {root_level} {nephews}".format(
levels=self.request.GET.get("levels", 100),
root_level=self.request.GET.get("root_level", None),
nephews=self.request.GET.get("nephews", 100)
)
template = Template(
"".join(("{% load menu_tags %}{% show_sub_menu ", args, " %}"))
)
template.render(context)
return context
[docs]class ShowBreadcrumbViewSet(ShowMenuViewSet):
"""
API Endpoint which calls the ``{% show_breadcrumb %}`` tag and returns
a serialized list of ``NavigationNodes``.
The following query parameters will be used to construct the argument list
which will be passed to the template tag.
===================== ================================================================
Query parameters Description
===================== ================================================================
start_level (int): After which level should the breadcrumb start? ``0`` equals home.
only_visible (int): Numeric boolean value(0 = False, 1 = True). To include all \n
pages, use ``only_visible=0``.
current_page (str): URL for the page that should be considered the `current_page` \n
when rendering the context.
===================== ================================================================
"""
def get_queryset(self):
context = self.render_context(self.get_context(self.request))
# We don't want nested children in the breadcrumb context.
# This should be a flat structure.
for node in context["ancestors"]:
del node.children
return context["ancestors"]
def render_context(self, context):
"""
Constructs the template tag arguments and render it.
Returns the context.
"""
args = "{start_level}".format(
start_level=self.request.GET.get("start_level", 0)
)
template = Template(
"".join(("{% load menu_tags %}{% show_breadcrumb ", args, " %}"))
)
template.render(context)
return context