You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/python/tutorial-django.md
+13-48Lines changed: 13 additions & 48 deletions
Original file line number
Diff line number
Diff line change
@@ -334,9 +334,11 @@ During your work with Django or any other library, you may want to examine the c
334
334
335
335
## Use a template to render a page
336
336
337
-
The app you've created so far in this tutorial generates only plain text web pages from Python code. Although it's possible to generate HTML directly in code, developers typically avoid such a practice because it's vulnerable to cross-site scripting (XSS) attacks. Instead, developers separate HTML markup from the code-generated data that gets inserted into that markup. **Templates** are a common approach to achieve this separation.
337
+
The app you've created so far in this tutorial generates only plain text web pages from Python code. Although it's possible to generate HTML directly in code, developers avoid such a practice because it opens the app to [cross-site scripting (XSS) attacks](https://en.wikipedia.org/wiki/Cross-site_scripting). In the `hello_there` function of this tutorial, for example, one might think to format the output in code with something like `content = "<h1>Hello there, " + clean_name + "!</h1>`, where the result in `content` is given directly to a browser. This opening allows an attacker to place malicious HTML, including JavaScript code, in the URL that ends up in `clean_name` and thus ends up being run in the browser.
338
338
339
-
A template is an HTML file that contains placeholders for values that the code provides at run time. The Django templating engine takes care of making the substitutions when rendering the page. The code, therefore, concerns itself only with data values and the template concerns itself only with markup. Django templates provide flexible options such as template inheritance, which allows you to define a base page with common markup and then build upon that base with page-specific additions.
339
+
A much better practice is to keep HTML out of your code entirely by using **templates**, so that your code is concerned only with data values and not with rendering.
340
+
341
+
In Django, a template is an HTML file that contains placeholders for values that the code provides at run time. The Django templating engine then takes care of making the substitutions when rendering the page, and provides automatic escaping to prevent XSS attacks (that is, if you tried using HTML in a data value, you would see the HTML rendered only as plain text). The code, therefore, concerns itself only with data values and the template concerns itself only with markup. Django templates provide flexible options such as template inheritance, which allows you to define a base page with common markup and then build upon that base with page-specific additions.
340
342
341
343
In this section, you start by creating a single page using a template. In subsequent sections, you configure the app to serve static files and then create multiple pages to the app that each contains a nav bar from a base template. Django templates also support control flow and iteration, as you see later in this tutorial in the context of template debugging.
342
344
@@ -348,17 +350,17 @@ In this section, you start by creating a single page using a template. In subseq
348
350
349
351
1. Inside the `hello` folder, create a folder named `templates`, and then another subfolder named `hello` to match the app name (this two-tiered folder structure is typical Django convention).
350
352
351
-
1. In the `templates/hello` folder, create a file named `hello_there.html` with the contents below. This template contains two placeholders named "title" and "content", which are delineated by pairs of curly braces, `\{{` and `}}`.
353
+
1. In the `templates/hello` folder, create a file named `hello_there.html` with the contents below. This template contains two placeholders for data values named "name", and "date", which are delineated by pairs of curly braces, `\{{` and `}}`. All other invariant text is part of the template, along with formatting markup (such as `<strong>`). As you can see, template placeholders can also include formatting, the expressions after the pipe `|` symbols, in this case using Django's built-in [date filter](https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#date) and [time filter](https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#time). The code, then needs only to pass the datetime *value* rather than a pre-formatted string:
352
354
353
355
```html
354
356
<!DOCTYPE html>
355
357
<html>
356
358
<head>
357
359
<meta charset="utf-8" />
358
-
<title>\{{ title }}</title>
360
+
<title>Hello, Django</title>
359
361
</head>
360
362
<body>
361
-
\{{ content }}
363
+
<strong>Hello there, \{{ name }}!</strong> It's \{{ date | date:'l, d F, Y' }} at \{{ date | time:'H:i:s' }}
362
364
</body>
363
365
</html>
364
366
```
@@ -369,48 +371,7 @@ In this section, you start by creating a single page using a template. In subseq
369
371
from django.shortcuts import render
370
372
```
371
373
372
-
1. Also in`views.py`, modify the `hello_there`functionto use `django.shortcuts.render` method to load a template and to provide the *template context* (the set of variables foruse within the template). `render_template` assumes that the first argument is relative to the `templates` folder. Typically, developers name the templates the same as the functions that use them, but matching names are not required because you always refer to the exact filenamein your code.
373
-
374
-
```python
375
-
# You can also remove the import re statement that's no longer used
376
-
377
-
def hello_there(request, name):
378
-
now = datetime.now()
379
-
formatted_now = now.strftime("%A, %d %B, %Y at %X")
380
-
381
-
# BAD CODE! Avoid inline HTML for security reason, plus templates automatically escape HTML content.
1. Start the program (inside or outside of the debugger, using `kb(workbench.action.debug.run)`), navigate to a /hello/name URL, and observe the results. Notice that the inline HTML, if you happen to write bad code like this, doesn't get rendered as HTML because the templating engine automatically escapes values used in placeholders. Automatic escaping prevent accidental vulnerabilities to injection attacks: developers often gather input from one page, or the URL, and use it as a value in another page through a template placeholder. Escaping also serves as a reminder that it's again best to keep HTML out of the code entirely.
395
-
396
-
For this reason, modify the template and view functionas follows to make each piece of content more specifically. While you're at it, move more of the text (including the title) into the template, along with the date/time formatting (using Django's built-in [date filter](https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#date) and [time filter](https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#time)):
397
-
398
-
Replace the contents of `templates/hello/hello_there.html` with the following:
399
-
400
-
```html
401
-
<!DOCTYPE html>
402
-
<html>
403
-
<head>
404
-
<meta charset="utf-8" />
405
-
<title>Hello, Django</title>
406
-
</head>
407
-
<body>
408
-
<strong>Hello there, \{{ name }}!</strong> It's \{{ date | date:'l, d F, Y' }} at \{{ date | time:'H:i:s' }}
409
-
</body>
410
-
</html>
411
-
```
412
-
413
-
Replace the `hello_there` function in `views.py` with the following:
374
+
1. Also in `views.py`, modify the `hello_there` function to use `django.shortcuts.render` method to load a template and to provide the *template context*. The context is simply the set of variables for use within the template. The `render` function takes the request object, followed by the path to to the template *relative to the `templates` folder*, then the context object. (Developers typically name the templates the same as the functions that use them, but matching names are not required because you always refer to the exact filename in your code.)
414
375
415
376
```python
416
377
def hello_there(request, name):
@@ -424,7 +385,11 @@ In this section, you start by creating a single page using a template. In subseq
424
385
)
425
386
```
426
387
427
-
1. Run the app again and navigate to a /hello/name URL to observe the expected result, then stop the app when you're done.
388
+
You can see that the code is now much simpler, and concerned only with data values, because the markup and formatting is all contained in the template.
389
+
390
+
1. Start the program (inside or outside of the debugger, using `kb(workbench.action.debug.run)`), navigate to a /hello/name URL, and observe the results.
391
+
392
+
1. Also try navigating to a /hello/name URL using a name like `<a%20value%20that%20could%20be%20HTML>` to see Django's automatic escaping at work. The "name" value shows up as plain text in the browser rather than as rendering an actual element.
Copy file name to clipboardExpand all lines: docs/python/tutorial-flask.md
+18-49Lines changed: 18 additions & 49 deletions
Original file line number
Diff line number
Diff line change
@@ -284,59 +284,18 @@ During your work with Flask or any other library, you may want to examine the co
284
284
285
285
## Use a template to render a page
286
286
287
-
The app you've created so far in this tutorial generates only plain text web pages from Python code. Although it's possible to generate HTML directly in code, developers typically avoid such a practice because it's vulnerable to cross-site scripting (XSS) attacks. Instead, developers separate HTML markup from the code-generated data that gets inserted into that markup. **Templates** are a common approach to achieve this separation.
287
+
The app you've created so far in this tutorial generates only plain text web pages from Python code. Although it's possible to generate HTML directly in code, developers avoid such a practice because it opens the app to [cross-site scripting (XSS) attacks](http://flask.pocoo.org/docs/1.0/security/#cross-site-scripting-xss). In the `hello_there` function of this tutorial, for example, one might think to format the output in code with something like `content = "<h1>Hello there, " + clean_name + "!</h1>`, where the result in `content` is given directly to a browser. This opening allows an attacker to place malicious HTML, including JavaScript code, in the URL that ends up in `clean_name` and thus ends up being run in the browser.
288
+
289
+
A much better practice is to keep HTML out of your code entirely by using **templates**, so that your code is concerned only with data values and not with rendering.
288
290
289
291
- A template is an HTML file that contains placeholders for values that the code provides at run time. The templating engine takes care of making the substitutions when rendering the page. The code, therefore, concerns itself only with data values and the template concerns itself only with markup.
290
-
- The default templating engine for Flask is [Jinja](http://jinja.pocoo.org/), which is installed automatically when you install Flask. This engine provides flexible options including template inheritance. With inheritance, you can define a base page with common markup and then build upon that base with page-specific additions.
292
+
- The default templating engine for Flask is [Jinja](http://jinja.pocoo.org/), which is installed automatically when you install Flask. This engine provides flexible options including automatic escapting (to prevent XSS attacks) and template inheritance. With inheritance, you can define a base page with common markup and then build upon that base with page-specific additions.
291
293
292
294
In this section, you create a single page using a template. In the sections that follow, you configure the app to serve static files, and then create multiple pages to the app that each contains a nav bar from a base template.
293
295
294
296
1. Inside the `hello_flask` folder, create a folder named `templates`, which is where Flask looks for templates by default.
295
297
296
-
1. In the `templates` folder, create a file named `hello_there.html` with the contents below. This template contains two placeholders named "title" and "content", which are delineated by pairs of curly braces, `\{{` and `}}`.
297
-
298
-
```html
299
-
<!DOCTYPE html>
300
-
<html>
301
-
<head>
302
-
<meta charset="utf-8" />
303
-
<title>\{{ title }}</title>
304
-
</head>
305
-
<body>
306
-
\{{ content }}
307
-
</body>
308
-
</html>
309
-
```
310
-
311
-
1. In `app.py`, import Flask's `render_template` function near the top of the file:
312
-
313
-
```python
314
-
from flask import render_template
315
-
```
316
-
317
-
1. Also in `app.py`, modify the `hello_there` function to use `render_template` to load a template and apply the named values. `render_template` assumes that the first argument is relative to the `templates` folder. Typically, developers name the templates the same as the functions that use them, but matching names are not required because you always refer to the exact filename in your code.
318
-
319
-
```python
320
-
@app.route("/hello/<name>")
321
-
def hello_there(name):
322
-
now = datetime.now()
323
-
formatted_now = now.strftime("%A, %d %B, %Y at %X")
324
-
325
-
# BAD CODE! Avoid inline HTML for security reason, plus templates automatically escape HTML content.
1. Start the program (inside or outside of the debugger, using `kb(workbench.action.debug.run)`), navigate to a /hello/name URL, and observe the results. Notice that the inline HTML, if you happen to write bad code like this, doesn't get rendered as HTML because the templating engine automatically escapes values used in placeholders. Automatic escaping prevent accidental vulnerabilities to injection attacks: developers often gather input from one page, or the URL, and use it as a value in another page through a template placeholder. Escaping also serves as a reminder that it's again best to keep HTML out of the code entirely.
336
-
337
-
For this reason, modify the template and view functionas follows to identify each piece of content more specifically. While you're at it, also move more of the text (including the title) and formatting concerns into the template and also handle the case where no name is given:
338
-
339
-
In `templates/hello_there.html`:
298
+
1. In the `templates` folder, create a file named `hello_there.html` with the contents below. This template contains two placeholders named "name" and "date", which are delineated by pairs of curly braces, `\{{` and `}}`. As you can see, you can also include formatting code in the template directly:
340
299
341
300
```html
342
301
<!DOCTYPE html>
@@ -355,7 +314,15 @@ In this section, you create a single page using a template. In the sections that
355
314
</html>
356
315
```
357
316
358
-
In `app.py`, change how you invoke the template and add a route to recognize the case without a name:
317
+
> **Tip**: Flask developers often use the [flask-babel](https://pythonhosted.org/Flask-Babel/) extension for date formatting, rather than `strftime`, as flask-babel takes locales and timezones into consideration.
318
+
319
+
1. In `app.py`, import Flask's `render_template`functionnear the top of the file:
320
+
321
+
```python
322
+
from flask import render_template
323
+
```
324
+
325
+
1. Also in`app.py`, modify the `hello_there`functionto use `render_template` to load a template and apply the named values (and add a route to recognize the case without a name). `render_template` assumes that the first argument is relative to the `templates` folder. Typically, developers name the templates the same as the functions that use them, but matching names are not required because you always refer to the exact filename in your code.
359
326
360
327
```python
361
328
@app.route("/hello/")
@@ -368,9 +335,11 @@ In this section, you create a single page using a template. In the sections that
368
335
)
369
336
```
370
337
371
-
> **Tip**: Flask developers often use the [flask-babel](https://pythonhosted.org/Flask-Babel/) extension for date formatting, rather than `strftime`, as flask-babel takes locales and timezones into consideration.
338
+
You can see that the code is now much simpler, and concerned only with data values, because the markup and formatting is all contained in the template.
339
+
340
+
1. Start the program (inside or outside of the debugger, using `kb(workbench.action.debug.run)`), navigate to a /hello/name URL, and observe the results.
372
341
373
-
1. Run the app again and navigate to a /hello/name URL to observe the expected result, then stop the app when you're done.
342
+
1. Also try navigating to a /hello/name URL using a name like `<a%20value%20that%20could%20be%20HTML>`to see Flask's automatic escaping at work. The "name" value shows up as plain text in the browser rather than as rendering an actual element.
0 commit comments