]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
:sparkles: Add docs and tests for Jinja2 templates (#186)
authorSebastián Ramírez <tiangolo@gmail.com>
Fri, 26 Apr 2019 14:49:15 +0000 (18:49 +0400)
committerGitHub <noreply@github.com>
Fri, 26 Apr 2019 14:49:15 +0000 (18:49 +0400)
* :sparkles: Add docs and tests for Jinja2 templates

* :art: Fix format in test, remove unused import

docs/src/static_files/tutorial001.py [new file with mode: 0644]
docs/src/templates/static/styles.css [new file with mode: 0644]
docs/src/templates/templates/item.html [new file with mode: 0644]
docs/src/templates/tutorial001.py [new file with mode: 0644]
docs/tutorial/static-files.md [new file with mode: 0644]
docs/tutorial/templates.md [new file with mode: 0644]
mkdocs.yml
tests/test_tutorial/test_templates/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_templates/test_tutorial001.py [new file with mode: 0644]

diff --git a/docs/src/static_files/tutorial001.py b/docs/src/static_files/tutorial001.py
new file mode 100644 (file)
index 0000000..5bcd594
--- /dev/null
@@ -0,0 +1,6 @@
+from fastapi import FastAPI
+from starlette.staticfiles import StaticFiles
+
+app = FastAPI()
+
+app.mount("/static", StaticFiles(directory="static"), name="static")
diff --git a/docs/src/templates/static/styles.css b/docs/src/templates/static/styles.css
new file mode 100644 (file)
index 0000000..dda2cdf
--- /dev/null
@@ -0,0 +1,3 @@
+h1 {
+    color: green;
+}
diff --git a/docs/src/templates/templates/item.html b/docs/src/templates/templates/item.html
new file mode 100644 (file)
index 0000000..a70287e
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<head>
+    <title>Item Details</title>
+    <link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
+</head>
+<body>
+    <h1>Item ID: {{ id }}</h1>
+</body>
+</html>
diff --git a/docs/src/templates/tutorial001.py b/docs/src/templates/tutorial001.py
new file mode 100644 (file)
index 0000000..0f00c3f
--- /dev/null
@@ -0,0 +1,16 @@
+from fastapi import FastAPI
+from starlette.requests import Request
+from starlette.staticfiles import StaticFiles
+from starlette.templating import Jinja2Templates
+
+app = FastAPI()
+
+app.mount("/static", StaticFiles(directory="static"), name="static")
+
+
+templates = Jinja2Templates(directory="templates")
+
+
+@app.get("/items/{id}")
+async def read_item(request: Request, id: str):
+    return templates.TemplateResponse("item.html", {"request": request, "id": id})
diff --git a/docs/tutorial/static-files.md b/docs/tutorial/static-files.md
new file mode 100644 (file)
index 0000000..31955fc
--- /dev/null
@@ -0,0 +1,34 @@
+You can serve static files automatically from a directory using <a href="https://www.starlette.io/staticfiles/" target="_blank">Starlette's Static Files</a>.
+
+## Install `aiofiles`
+
+First you need to install `aiofiles`:
+
+```bash
+pip install aiofiles
+```
+
+## Use `StaticFiles`
+
+* Import `StaticFiles` from Starlette.
+* "Mount" it the same way you would <a href="https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/" target="_blank">mount a Sub-Application</a>.
+
+```Python hl_lines="2 6"
+{!./src/static_files/tutorial001.py!}
+```
+
+Then you could have a directory `./static/` with some files that will be served directly.
+
+## Details
+
+The first `"/static"` refers to the sub-path this "sub-application" will be "mounted" on. So, any path that starts with `"/static"` will be handled by it.
+
+The `directory="static"` refers to the name of the directory that contains your static files.
+
+The `name="static"` gives it a name that can be used internally by **FastAPI**.
+
+All these parameters can be different than "`static`", adjust them with the needs and specific details of your own application.
+
+## More info
+
+For more details and options check <a href="https://www.starlette.io/staticfiles/" target="_blank">Starlette's docs about Static Files</a>.
diff --git a/docs/tutorial/templates.md b/docs/tutorial/templates.md
new file mode 100644 (file)
index 0000000..a909ece
--- /dev/null
@@ -0,0 +1,67 @@
+You can use any template engine you want with **FastAPI**.
+
+A common election is Jinja2, the same one used by Flask and other tools.
+
+Starlette has utilities to configure it easily that you can use directly in your **FastAPI** application.
+
+## Install dependencies
+
+Install `jinja2`:
+
+```bash
+pip install jinja2
+```
+
+If you need to also serve static files (as in this example), install `aiofiles`:
+
+```bash
+pip install aiofiles
+```
+
+## Using `Jinja2Templates`
+
+* Import `Jinja2Templates` form Starlette.
+* Create a `templates` object that you can re-use later.
+* Declare a `Request` parameter in the *path operation* that will return a template.
+* Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context".
+
+```Python hl_lines="4 11 15 16"
+{!./src/templates/tutorial001.py!}
+```
+
+!!! note
+    Notice that you have to pass the `request` as part of the key-value pairs in the context for Jinja2. So, you also have to declare it in your *path operation*.
+
+## Writing templates
+
+Then you can write a template at `templates/item.html` with:
+
+```jinja hl_lines="7"
+{!./src/templates/templates/item.html!}
+```
+
+It will show the `id` taken from the "context" `dict` you passed:
+
+```Python
+{"request": request, "id": id}
+```
+
+## Templates and static files
+
+And you can also use `url_for()` inside of the template, and use it, for example, with the `StaticFiles` you mounted.
+
+```jinja hl_lines="4"
+{!./src/templates/templates/item.html!}
+```
+
+In this example, it would link to a CSS file at `static/styles.css` with:
+
+```CSS hl_lines="4"
+{!./src/templates/static/styles.css!}
+```
+
+And because you are using `StaticFiles`, that CSS file would be served automatically by your **FastAPI** application at the URL `/static/styles.css`.
+
+## More details
+
+For more details, including how to test templates, check <a href="https://www.starlette.io/templates/" target="_blank">Starlette's docs on templates</a>.
\ No newline at end of file
index 57712ec12c1c0af200b35ec8b82cacd51f25d2a3..d5b81d5433763b2151729b3484c76bd7bc8d7568 100644 (file)
@@ -73,6 +73,8 @@ nav:
         - Background Tasks: 'tutorial/background-tasks.md'
         - Sub Applications - Behind a Proxy: 'tutorial/sub-applications-proxy.md'
         - Application Configuration: 'tutorial/application-configuration.md'
+        - Static Files: 'tutorial/static-files.md'
+        - Templates: 'tutorial/templates.md'
         - GraphQL: 'tutorial/graphql.md'
         - WebSockets: 'tutorial/websockets.md'
         - 'Events: startup - shutdown': 'tutorial/events.md'
diff --git a/tests/test_tutorial/test_templates/__init__.py b/tests/test_tutorial/test_templates/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_templates/test_tutorial001.py b/tests/test_tutorial/test_templates/test_tutorial001.py
new file mode 100644 (file)
index 0000000..f53030a
--- /dev/null
@@ -0,0 +1,19 @@
+import shutil
+
+from starlette.testclient import TestClient
+
+
+def test_main():
+    shutil.copytree("./docs/src/templates/templates/", "./templates")
+    shutil.copytree("./docs/src/templates/static/", "./static")
+    from templates.tutorial001 import app
+
+    client = TestClient(app)
+    response = client.get("/items/foo")
+    assert response.status_code == 200
+    assert b"<h1>Item ID: foo</h1>" in response.content
+    response = client.get("/static/styles.css")
+    assert response.status_code == 200
+    assert b"color: green;" in response.content
+    shutil.rmtree("./templates")
+    shutil.rmtree("./static")