flex_menu.menu#

Menu and MenuItem, the tree that menus are declared with.

Module Contents#

Classes#

_NoParentType

Sentinel distinguishing “no parent specified” from “explicitly no parent”.

MenuItem

A menu item that is a clickable link, a container, or a non-clickable item.

Menu

Top-level menu container that automatically registers itself to the root.

Functions#

_should_log_url_failures

Report whether URL resolution failures should be logged.

Data#

API#

_should_log_url_failures()[source]#

Report whether URL resolution failures should be logged.

Failed URL resolution is often expected, such as a menu item hidden because the user lacks permission or an optional view isn’t installed, so logging defaults to DEBUG and can be overridden with the FLEX_MENUS[‘log_url_failures’] setting.

Returns:

True if URL failures should be logged, False otherwise.

class _NoParentType[source]#

Sentinel distinguishing “no parent specified” from “explicitly no parent”.

_NO_PARENT#

‘_NoParentType(…)’

class MenuItem(name: str, view_name: str = '', url: str | collections.abc.Callable = '', params: dict | None = None, parent: Optional[flex_menu.menu.MenuItem] | flex_menu.menu._NoParentType = None, children: list[flex_menu.menu.MenuItem] | None = None, check: collections.abc.Callable | bool = True, extra_context: dict | None = None, **kwargs)[source]#

Bases: anytree.Node

A menu item that is a clickable link, a container, or a non-clickable item.

A MenuItem is a clickable link (has url/view_name), a container/parent (has children), or a non-clickable item (headers, dividers). It cannot have both a URL and children - it must be either a link OR a container, not both.

Parameters:
  • name – Unique identifier for this menu item.

  • view_name – Django URL name for reverse resolution.

  • url – Static URL string or callable returning URL.

  • params – Query parameters dict to append to URL.

  • parent – Parent menu item (or None for root-level items).

  • children – List of child menu items.

  • check – A callable(request, **kwargs) -> bool or a boolean value.

  • extra_context – Additional context for template rendering.

  • **kwargs – Additional attributes for the node.

Processing a copy (see process()) also sets visible, selected and the resolved url on that copy.

Variables:

request – The current request, set on the copy process() returns.

Raises:

ValueError – If both URL/view_name and children are provided.

Initialization

request: django.core.handlers.wsgi.WSGIRequest | None#

None

_processed_children: list[flex_menu.menu.MenuItem]#

None

_original_children: tuple[flex_menu.menu.MenuItem, ...]#

None

_cached_url: str | None#

None

__str__() → str[source]#

Show the menu item’s name.

__getitem__(name: str) → flex_menu.menu.MenuItem[source]#

Get child by name using bracket notation.

__iter__()[source]#

Iterate over children.

property has_url: bool#

True if this menu item has a URL (view_name or url).

property has_children: bool#

True if this menu has child items.

property visible_children: list[flex_menu.menu.MenuItem]#

Return processed, visible children (after processing).

property has_visible_children: bool#

True if this menu has visible children after processing.

property is_parent: bool#

Alias for has_children.

property is_leaf: bool#

True if this is a leaf node (no children).

property is_clickable: bool#

True if this item can be clicked (has URL).

property depth: int#

Depth in the tree, where 0 is the root, 1 is top-level items, and so on.

append(child: flex_menu.menu.MenuItem) → None[source]#

Append a child menu item.

Parameters:

child – The child menu item to append.

Raises:

ValueError – If this item has a URL (cannot have both URL and children).

extend(children: list[flex_menu.menu.MenuItem]) → None[source]#

Append multiple child menu items.

Parameters:

children – List of child menu items to append.

Raises:

ValueError – If this item has a URL (cannot have both URL and children).

insert(children: MenuItem | list[MenuItem], position: int) → None[source]#

Insert child menu items at a specified position.

Parameters:
  • children – A child or list of children to insert.

  • position – Position index to insert at.

Raises:

ValueError – If this item has a URL (cannot have both URL and children).

insert_after(child: flex_menu.menu.MenuItem, named: str) → None[source]#

Insert a child menu item after an existing child with specified name.

Parameters:
  • child – The new child menu item to insert.

  • named – The name of the existing child after which to insert.

Raises:

ValueError – If no child with specified name exists or if this item has a URL.

pop(name: str | None = None) → flex_menu.menu.MenuItem[source]#

Remove a child node or detach the current node from its parent.

Parameters:

name – The name of the child to remove. If None, removes this node.

Returns:

The removed node.

Raises:

ValueError – If no child with the specified name exists.

get(name: str, maxlevel: int | None = None) → Optional[flex_menu.menu.MenuItem][source]#

Find a child node by name.

Parameters:
  • name – The name of the child node to find.

  • maxlevel – The maximum depth to search. 1 = direct children only, 2 = children and grandchildren, etc.

Returns:

The child node, or None if not found.

print_tree() → str[source]#

Print the menu tree structure.

Returns:

A string representation of the tree.

check(request, **kwargs) → bool[source]#

Check if the menu item is visible based on the request.

Parameters:
  • request – The HTTP request object.

  • **kwargs – Additional arguments for custom check functions.

Returns:

True if the menu item is visible, False otherwise.

process(request, **kwargs) → flex_menu.menu.MenuItem[source]#

Process the menu item for a specific request.

Creates a processed copy with request-specific state to avoid race conditions. For items with children, recursively processes all children.

Parameters:
  • request – The HTTP request object.

  • **kwargs – Additional arguments passed to check functions and URL resolution.

Returns:

A processed copy of this menu item with request-specific state.

_create_request_copy() → flex_menu.menu.MenuItem[source]#

Create a shallow copy for request processing.

Creates a copy that maintains the tree structure so depth calculations work. The copy will be detached from the global root but maintain proper parent-child relationships.

resolve_url(*args, **kwargs) → str | None[source]#

Resolve the URL for this menu item.

Supports three types of URLs: - Django view names (resolved via reverse()) - Static URL strings - Callable functions that return URLs

Parameters:
  • *args – Positional arguments for URL resolution.

  • **kwargs – Keyword arguments for URL resolution. Extra kwargs not needed for the URL pattern will be filtered out automatically.

Returns:

The resolved URL string, or None if resolution fails.

static _normalized_path(value: str | django.utils.functional.Promise) → str[source]#

Strip query string/fragment and any single trailing slash for comparison.

A menu declared at module level resolves its URLs with reverse_lazy, because the URLconf is not loaded when the module is imported. That hands the item a lazy proxy, and urlsplit only accepts str or bytes, so the proxy is resolved here before the split.

match_url() → bool[source]#

Check if the menu item points at the current request.

Items with a view_name are matched against the request’s resolved view name, which identifies the destination Django resolved to rather than a reconstructed path string. That handles a request whose path carries kwargs for a different object, an i18n language prefix, or query string/trailing-slash variation, all of which a raw path comparison gets wrong.

Items configured with a literal url or a callable have no resolved view to compare against, so they fall back to a normalized path comparison (query string, fragment and trailing slash ignored).

Returns:

True if the item matches the current request, False otherwise.

root#

‘MenuItem(…)’

class Menu(name: str, children: list[flex_menu.menu.MenuItem] | None = None, check: collections.abc.Callable | bool = True, extra_context: dict | None = None, **kwargs)[source]#

Bases: flex_menu.menu.MenuItem

Top-level menu container that automatically registers itself to the root.

This is a convenience class for defining menus. It’s functionally identical to MenuItem but automatically attaches to the global root menu, and cannot have a URL (it is a container only).

Parameters:
  • name – Unique identifier for this menu.

  • children – List of child menu items.

  • check – A callable(request, **kwargs) -> bool or a boolean value.

  • extra_context – Additional context for template rendering.

  • **kwargs – Additional attributes for the node.

Example

NavMenu = Menu(
    "main_nav",
    children=[
        MenuItem(name="home", label="Home", view_name="home"),
        MenuItem(name="about", label="About", view_name="about"),
    ],
)

Then in a template:

{% render_menu 'main_nav' renderer='bootstrap5' %}

Initialization

_create_request_copy() → flex_menu.menu.MenuItem[source]#

Use MenuItem’s copy construction instead of Menu’s root-attaching one.