flex_menu.menu#
Menu and MenuItem, the tree that menus are declared with.
Module Contents#
Classes#
Sentinel distinguishing “no parent specified” from “explicitly no parent”. |
|
A menu item that is a clickable link, a container, or a non-clickable item. |
|
Top-level menu container that automatically registers itself to the root. |
Functions#
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.NodeA 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) -> boolor a boolean value.extra_context – Additional context for template rendering.
**kwargs – Additional attributes for the node.
Processing a copy (see
process()) also setsvisible,selectedand the resolvedurlon 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
- __getitem__(name: str) → flex_menu.menu.MenuItem[source]#
Get child by name using bracket notation.
- 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_nameare 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
urlor 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.MenuItemTop-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) -> boolor 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.