* Use jinja2 for a default template configuration

* Add release notes
This commit is contained in:
Tom Christie 2018-11-08 16:14:14 +00:00 committed by GitHub
parent 291255b24c
commit 2ef21f49c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 8 deletions

View File

@ -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]`.

View File

@ -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]`.

View File

@ -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

View File

@ -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=...)`.

View File

@ -2,6 +2,7 @@
aiofiles
graphene
itsdangerous
jinja2
python-multipart
pyyaml
requests

View File

@ -1 +1 @@
__version__ = "0.8.0"
__version__ = "0.8.1"

View File

@ -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

23
tests/test_templates.py Normal file
View File

@ -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>"