mirror of https://github.com/encode/starlette.git
Jinja2 (#198)
* Use jinja2 for a default template configuration * Add release notes
This commit is contained in:
parent
291255b24c
commit
2ef21f49c9
|
@ -80,10 +80,11 @@ Starlette does not have any hard dependencies, but the following are optional:
|
|||
|
||||
* [`requests`][requests] - Required if you want to use the `TestClient`.
|
||||
* [`aiofiles`][aiofiles] - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* [`jinja2`][jinja2] - Required if you want to use the default template configuration.
|
||||
* [`python-multipart`][python-multipart] - Required if you want to support form parsing, with `request.form()`.
|
||||
* [`graphene`][graphene] - Required for `GraphQLApp` support.
|
||||
* [`itsdangerous`][itsdangerous] - Required for `SessionMiddleware` support.
|
||||
* [`pyyaml`][pyyaml] - Required for `SchemaGenerator` support.
|
||||
* [`graphene`][graphene] - Required for `GraphQLApp` support.
|
||||
* [`ujson`][ujson] - Required if you want to use `UJSONResponse`.
|
||||
|
||||
You can install all of these with `pip3 install starlette[full]`.
|
||||
|
|
|
@ -79,10 +79,11 @@ Starlette does not have any hard dependencies, but the following are optional:
|
|||
|
||||
* [`requests`][requests] - Required if you want to use the `TestClient`.
|
||||
* [`aiofiles`][aiofiles] - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* [`jinja2`][jinja2] - Required if you want to use the default template configuration.
|
||||
* [`python-multipart`][python-multipart] - Required if you want to support form parsing, with `request.form()`.
|
||||
* [`graphene`][graphene] - Required for `GraphQLApp` support.
|
||||
* [`itsdangerous`][itsdangerous] - Required for `SessionMiddleware` support.
|
||||
* [`pyyaml`][pyyaml] - Required for `SchemaGenerator` support.
|
||||
* [`graphene`][graphene] - Required for `GraphQLApp` support.
|
||||
* [`ujson`][ujson] - Required if you want to use `UJSONResponse`.
|
||||
|
||||
You can install all of these with `pip3 install starlette[full]`.
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
## 0.8.1
|
||||
|
||||
## Templating
|
||||
|
||||
* Add a default templating configuration with Jinja2.
|
||||
|
||||
Allows the following:
|
||||
|
||||
```python
|
||||
app = Starlette(template_directory="templates")
|
||||
|
||||
@app.route('/')
|
||||
async def homepage(request):
|
||||
# `url_for` is available inside the template.
|
||||
template = app.get_template('index.html')
|
||||
content = template.render(request=request)
|
||||
return HTMLResponse(content)
|
||||
```
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Exceptions
|
||||
|
|
|
@ -1,8 +1,34 @@
|
|||
Starlette is not coupled to any particular templating engine, but Jinja2
|
||||
provides an excellent choice.
|
||||
Starlette is not *strictly* coupled to any particular templating engine, but
|
||||
Jinja2 provides an excellent choice.
|
||||
|
||||
Here we're going to take a look at a complete example of how you can configure
|
||||
a Jinja2 environment together with Starlette.
|
||||
The `Starlette` application class provides a simple way to get `jinja2`
|
||||
configured. This is probably what you want to use by default.
|
||||
|
||||
```python
|
||||
app = Starlette(debug=True, template_directory='templates')
|
||||
app.mount('/static', StaticFiles(directory='statics'), name='static')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
async def homepage(request):
|
||||
template = app.get_template('index.html')
|
||||
content = template.render(request=request)
|
||||
return HTMLResponse(content)
|
||||
```
|
||||
|
||||
If you include `request` in the template context, then the `url_for` function
|
||||
will also be available within your template code.
|
||||
|
||||
The Jinja2 `Environment` instance is available as `app.template_env`.
|
||||
|
||||
## Handling templates explicitly
|
||||
|
||||
If you don't want to use `jinja2`, or you don't want to rely on
|
||||
Starlette's default configuration you can configure a template renderer
|
||||
explicitly instead.
|
||||
|
||||
Here we're going to take a look at an example of how you can explicitly
|
||||
configure a Jinja2 environment together with Starlette.
|
||||
|
||||
```python
|
||||
from starlette.applications import Starlette
|
||||
|
@ -34,6 +60,9 @@ async def homepage(request):
|
|||
return HTMLResponse(content)
|
||||
```
|
||||
|
||||
This gives you the equivalent of the default `app.get_template()`, but we've
|
||||
got all the configuration explicitly out in the open now.
|
||||
|
||||
The important parts to note from the above example are:
|
||||
|
||||
* The StaticFiles app has been mounted with `name='static'`, meaning we can use `app.url_path_for('static', path=...)` or `request.url_for('static', path=...)`.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
aiofiles
|
||||
graphene
|
||||
itsdangerous
|
||||
jinja2
|
||||
python-multipart
|
||||
pyyaml
|
||||
requests
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "0.8.0"
|
||||
__version__ = "0.8.1"
|
||||
|
|
|
@ -11,7 +11,7 @@ from starlette.types import ASGIApp, ASGIInstance, Scope
|
|||
|
||||
|
||||
class Starlette:
|
||||
def __init__(self, debug: bool = False) -> None:
|
||||
def __init__(self, debug: bool = False, template_directory: str = None) -> None:
|
||||
self._debug = debug
|
||||
self.router = Router()
|
||||
self.lifespan_handler = LifespanHandler()
|
||||
|
@ -20,6 +20,7 @@ class Starlette:
|
|||
self.exception_middleware, debug=debug
|
||||
)
|
||||
self.schema_generator = None # type: typing.Optional[BaseSchemaGenerator]
|
||||
self.template_env = self.load_template_env(template_directory)
|
||||
|
||||
@property
|
||||
def routes(self) -> typing.List[BaseRoute]:
|
||||
|
@ -35,6 +36,26 @@ class Starlette:
|
|||
self.exception_middleware.debug = value
|
||||
self.error_middleware.debug = value
|
||||
|
||||
def load_template_env(self, template_directory: str = None) -> typing.Any:
|
||||
if template_directory is None:
|
||||
return None
|
||||
|
||||
# Import jinja2 lazily.
|
||||
import jinja2
|
||||
|
||||
@jinja2.contextfunction
|
||||
def url_for(context: dict, name: str, **path_params: typing.Any) -> str:
|
||||
request = context["request"]
|
||||
return request.url_for(name, **path_params)
|
||||
|
||||
loader = jinja2.FileSystemLoader(str(template_directory))
|
||||
env = jinja2.Environment(loader=loader, autoescape=True)
|
||||
env.globals["url_for"] = url_for
|
||||
return env
|
||||
|
||||
def get_template(self, name: str) -> typing.Any:
|
||||
return self.template_env.get_template(name)
|
||||
|
||||
@property
|
||||
def schema(self) -> dict:
|
||||
assert self.schema_generator is not None
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import os
|
||||
|
||||
from starlette.applications import Starlette
|
||||
from starlette.responses import HTMLResponse
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
|
||||
def test_templates(tmpdir):
|
||||
path = os.path.join(tmpdir, "index.html")
|
||||
with open(path, "w") as file:
|
||||
file.write("<html>Hello, <a href='{{ url_for('homepage') }}'>world</a></html>")
|
||||
|
||||
app = Starlette(debug=True, template_directory=tmpdir)
|
||||
|
||||
@app.route("/")
|
||||
async def homepage(request):
|
||||
template = app.get_template("index.html")
|
||||
content = template.render(request=request)
|
||||
return HTMLResponse(content)
|
||||
|
||||
client = TestClient(app)
|
||||
response = client.get("/")
|
||||
assert response.text == "<html>Hello, <a href='http://testserver/'>world</a></html>"
|
Loading…
Reference in New Issue