Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add extra_context to NavGroup and NavItem #34

Merged
merged 7 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/django_simple_nav/nav.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from dataclasses import dataclass
from dataclasses import field
from typing import Any

from django.http import HttpRequest
from django.template.loader import render_to_string
Expand Down Expand Up @@ -38,20 +39,29 @@ class NavGroup:
items: list[NavGroup | NavItem]
url: str | None = None
permissions: list[str] = field(default_factory=list)
extra_context: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class NavItem:
title: str
url: str
permissions: list[str] = field(default_factory=list)
extra_context: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class RenderedNavItem:
item: NavItem | NavGroup
request: HttpRequest

def __getattr__(self, name: str) -> Any:
try:
return self.item.extra_context[name]
except KeyError as err:
msg = f"{self.item!r} object has no attribute {name!r}"
raise AttributeError(msg) from err

@property
def title(self) -> str:
return mark_safe(self.item.title)
Expand Down
36 changes: 36 additions & 0 deletions tests/test_nav.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from django.utils.module_loading import import_string
from model_bakery import baker

from django_simple_nav.nav import NavItem
from django_simple_nav.nav import RenderedNavItem
from tests.navs import DummyNav
from tests.utils import count_anchors

Expand Down Expand Up @@ -96,3 +98,37 @@ def test_nav_render_from_request_with_template_name(req):
rendered_template = DummyNav.render_from_request(req, "tests/alternate.html")

assert "This is an alternate template." in rendered_template


def test_extra_context(req):
item = NavItem(
title="Test",
url="/test/",
extra_context={"foo": "bar"},
)

rendered_item = RenderedNavItem(item, req)

assert rendered_item.foo == "bar"


def test_extra_context_with_no_extra_context(req):
item = NavItem(
title="Test",
url="/test/",
)
rendered_item = RenderedNavItem(item, req)

with pytest.raises(AttributeError):
assert rendered_item.foo == "bar"


def test_extra_context_shadowing(req):
item = NavItem(
title="Test",
url="/test/",
extra_context={"title": "Shadowed"},
)
rendered_item = RenderedNavItem(item, req)

assert rendered_item.title == "Test"