django-components: "context" is empty in template method

So I have this component:

class Svg(component.Component):
    def context(self, name: str, css_class: str = "", title: str = "", **attrs) -> Dict:
        return {"name": name, "css_class": css_class, "title": title, **attrs}

    def template(self, context: Dict) -> str:
        print(context)
        return f"svg/_{context['name']}.svg"

The template name is assigned dynamically depending on the name of the SVG:

{% component “svg” name=“download” %}

However the template() method raises a KeyError, as the key “name” is not in the context: it’s empty.

What is the order of execution here? Is template() called before context() ? If so, how do I access variables to be able to set the template name dynamically?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 17 (17 by maintainers)

Most upvoted comments

I just dropped support for all Python and Django versions not officially supported my Django itself. This means we’re now Python 3.6+ and Django 2.2+. Hope this makes things easier to hack on going forward 😃

@rbeard0330 Is this related to your latest optimization?

Yes, definitely. I think I mentioned in the PR that the change was breaking for this kind of use–fundamentally, you can’t compile the component when the rest of the template is compiled if the identity of the component template changes each time the template is rendered, and you’ll need to compile it fresh every render. A couple thoughts:

  • The native {% include %} tag can cover a lot of potential use cases by passing it a dynamic template to load.
  • The easiest fix would probably be to add a flag as either a setting or a class attribute of each Component that would control whether the component tries to compile itself at compile time (with an empty context) or waits until render time and uses the full context.
  • Agreed that, as currently written, the get_template method doesn’t really need to be a method, but removing it or changing its signature would break existing code.