.. _cookbook-main-menu: Main menu --------- How do I control which menu items are shown for a user? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.include Using `include` you can control which menu items are shown for a given user. This also controls access, so you can know that your menu and your access control are always in sync. .. code-block:: python menu = MainMenu( items=dict( albums=M( view=albums_view, ), artists=M( view=artists_view, include=lambda user, **_: user.is_staff, ), ), ) .. raw:: html
▼ Hide result
Toggle structure
.. raw:: html
▼ Hide result
Toggle structure
How do I control the display name of a menu item? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.display_name By default the display name is derived from the `name` of the `M` object. So given: .. code-block:: python menu = MainMenu( items=dict( albums=M(view=albums_view), ), ) .. raw:: html
▼ Hide result
Toggle structure
The `name` would be "albums", and the display name is automatically derived as "Albums". The translation from `name` to `display_name` replaces `_` with space, runs `gettext_lazy()` on the result, and then capitalizes that. If you want to do something else, pass the `display_name` parameter: .. code-block:: python menu = MainMenu( items=dict( albums=M( view=albums_view, display_name=gettext_lazy('Discography'), ), ), ) .. raw:: html
▼ Hide result
Toggle structure
Note that `display_name` can be a function too. How do I add sub-paths for a menu item? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.paths Since the menu system can control access, it is useful to nest path mappings under a specific menu item without showing them in the menu. This is done with the `paths` argument: .. code-block:: python menu = MainMenu( items=dict( albums=M( view=albums_view, paths=[ path('/edit/', edit_album_view), ], ), ), ) .. raw:: html
► Show result
Toggle structure
How do I add external links in the menu? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.url .. uses EXTERNAL Use the special value `EXTERNAL` for the `view` argument, and use `url` argument: .. code-block:: python menu = MainMenu( items=dict( albums=M( view=EXTERNAL, url='https://docs.iommi.rocks', ), ), ) .. raw:: html
▼ Hide result
Toggle structure
Note the icon added by default for an external link. This is configurable via the `icon_formatter` on your `Style`. How do I nest menu items? ~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.items .. uses M.open You can create a menu hierarchy with the `items` argument, which produces expandable sections. iommi will open the menu items that match the current URL by default. You can also force a submenu to be open with the `open` argument: .. code-block:: python menu = MainMenu( items=dict( things=M( view=things_view, open=True, # force open items=dict( albums=M( view=albums_view, ), artists=M( view=artists_view, ) ), ), ), ) .. raw:: html
▼ Hide result
Toggle structure
The `open` argument can be a callable. How do I put arbitrary html in the menu? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.template With the `template` argument you can put arbitrary html into menu items: .. code-block:: python menu = MainMenu( items=dict( albums=M( view=EXTERNAL, template=Template('''
  •          
  • ''') ), ), ) .. raw:: html
    ▼ Hide result
    Toggle structure
    Note that you want to include the `
  • ` tag. You can also override the base template via your `Style`. How do I show which specific object I am on in the menu? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.path .. uses M.url .. uses M.params If you have a list of objects and you click into one of them, you might want to show that item in the menu, and potentially also sub-pages for that item. You do that by using iommi path decoders, and mapping everything together with `display_name`, `path`, `params` and `url`: .. code-block:: python menu = MainMenu( items=dict( albums=M( view=albums_view, items=dict( album=M( view=album_view, display_name=lambda album, **_: str(album), path='/', params={'album'}, url=lambda album, **_: f'/albums/{album.pk}/', ), ) ), ), ) .. raw:: html
    ▼ Hide result
    Toggle structure
    How do I make a data driven dynamic submenu? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.items There can be cases where you want a dynamic submenu where the items come from the database. To do this, specify `items` as a callable. Note that urls here can't be mapped to paths, as paths need to be known at startup. .. code-block:: python menu = MainMenu( items=dict( albums=M( view=albums_view, items=lambda **_: { f'album_{album.pk}': M( view=EXTERNAL, display_name=str(album), url=album.get_absolute_url(), ) for album in Album.objects.all() } ) ), ) .. raw:: html
    ▼ Hide result
    Toggle structure
    How do I use the menu for access control and path mapping without rendering into the menu? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. uses M.render The access control and path mapping of `M` items is very handy, but sometimes you don't want to show some URL in the sidebar menu. Use `render` to accomplish this: .. code-block:: python menu = MainMenu( items=dict( albums=M( view=albums_view, render=False, ) ), )