westerveltco / django-simple-nav

A simple, flexible, and extensible navigation menu for Django
https://django-simple-nav.westervelt.dev
MIT License
12 stars 0 forks source link

Get `AttributeError: 'SafeString' object has no attribute 'resolve'` randomly #45

Closed joshuadavidthomas closed 9 months ago

joshuadavidthomas commented 9 months ago

In clicking around on the demo in #42, this error sometimes pops up. It's random and inconsistent.

  File "/home/josh/projects/django-simple-nav/.nox/demo/lib/python3.12/site-packages/django/template/base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/josh/projects/django-simple-nav/.nox/demo/lib/python3.12/site-packages/django/template/base.py", line 961, in render_annotated
    return self.render(context)
           ^^^^^^^^^^^^^^^^^^^^
  File "/home/josh/projects/django-simple-nav/.nox/demo/lib/python3.12/site-packages/django_simple_nav/templatetags/django_simple_nav.py", line 32, in render
    self.nav = self.nav.resolve(context)
               ^^^^^^^^^^^^^^^^
AttributeError: 'SafeString' object has no attribute 'resolve'
2024-02-23 16:21:17,484 django.server ERROR    "GET /tailwind/ HTTP/1.1" 500 145
joshuadavidthomas commented 9 months ago

ChatGPT suggested the fact that we were setting self.nav back to the resolved template variable is the cause. Implementing it's fix seems to have fixed the issue:

# django_template_nav/templatetags/django_template_nav.py

...

class DjangoSimpleNavNode(template.Node):
    ...

    def render(self, context):
        try:
            resolved_nav = self.nav.resolve(context)
            resolved_template_name = (
                self.template_name.resolve(context) if self.template_name else None
            )
        except template.VariableDoesNotExist as err:
            raise template.TemplateSyntaxError(
                f"Variable does not exist: {err}"
            ) from err

        if isinstance(resolved_nav, str):
            try:
                nav = import_string(resolved_nav)()
            except ImportError as err:
                raise template.TemplateSyntaxError(
                    f"Failed to import: {resolved_nav}"
                ) from err
        else:
            nav = resolved_nav

        if not hasattr(nav, "render"):
            raise template.TemplateSyntaxError(
                "The object does not have a 'render' method."
            )

        return nav.render(context["request"], resolved_template_name)