litestar-org / litestar

Production-ready, Light, Flexible and Extensible ASGI API framework | Effortlessly Build Performant APIs
https://litestar.dev/
MIT License
5.64k stars 382 forks source link

template additional config #170

Closed mybigman closed 2 years ago

mybigman commented 2 years ago

How can this be achieved with the current way the template config is used?

templates = Jinja2Templates(directory="templates")
templates.env.globals[’flashed_messages’] = flashed_messages
peterschutt commented 2 years ago

I cannot see an obvious way, nor any mention of setting globals in the docs, so hopefully I haven't missed anything.

The jinja Environment is constructed in starlite.template.jinja.JinjaTemplateEngine:

class JinjaTemplateEngine(TemplateEngineProtocol[JinjaTemplate]):
    """Template engine using the jinja templating library"""

    def __init__(self, directory: Union[DirectoryPath, List[DirectoryPath]]) -> None:
        super().__init__(directory)
        loader = FileSystemLoader(searchpath=directory)
        self.engine = Environment(loader=loader, autoescape=True)

According to jinja docs that Environment object has a globals attribute which is a dict for storing those variables in.

So maybe we could do something like:

templates = TemplateConfig(
    directory="templates", engine=JinjaTemplateEngine, globals={"flashed_messages": flashed_messages}
)
mybigman commented 2 years ago

@peterschutt are you saying that you can implement into the code base or it should already work?

I have tried that but errors with UndefinedError: 'flashed_messages' is undefined when trying to call it in the template.

peterschutt commented 2 years ago

That is a suggestion of a potential api design to solve the problem you have, it would need to be implemented.

Goldziher commented 2 years ago

+1, We can also expose and propagate **kwargs

peterschutt commented 2 years ago

@mybigman are you happy enough that you can do what you want to do with the solution in #172?

mybigman commented 2 years ago

@peterschutt looks like it should do the trick.

I came across this yesterday, does it also cover the ability to do -

jinja partials

from starlette.templating import Jinja2Templates

import jinja_partials

templates = Jinja2Templates("tests/test_templates")

jinja_partials.register_starlette_extensions(templates)
peterschutt commented 2 years ago

Yeh I think that would work easy enough, as you can just work with the Environment that is passed back to you.

from jinja_partials import generate_render_partial

def engine_callback(templates: JinjaTemplateEngine) -> JinjaTemplateEngine:

    def renderer(template_name: str, **data: Any) -> str:
        return templates.get_template(template_name).render(**data)

    templates.engine.globals.update(render_partial=generate_render_partial(renderer))

template_config = TemplateConfig(
    directory="templates", engine=JinjaTemplateEngine, engine_callback=engine_callback
)

Haven't tested though, let me know if it doesn't work for you.

mybigman commented 2 years ago

@peterschutt just tested and it appears all is working.

thanks mate

peterschutt commented 2 years ago

No probs. I'd not come across that lib before, but seems pretty neat. Random fact: it belongs to the guy that does the "Talk Python to Me" podcast.

mybigman commented 2 years ago

yeh likewise... as mentioned only come across the other day and thought the same pretty clever.