or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blueprints.mdcli.mdconfiguration.mdcontext-globals.mdcore-application.mdhelpers.mdindex.mdjson-support.mdrequest-response.mdrouting.mdsessions.mdsignals.mdtemplates.mdtesting.md

templates.mddocs/

0

# Templates

1

2

Flask uses Jinja2 as its template engine, providing powerful template rendering capabilities with template inheritance, macros, filters, and automatic escaping for security.

3

4

## Capabilities

5

6

### Template Rendering Functions

7

8

Functions for rendering templates with context data.

9

10

```python { .api }

11

def render_template(template_name_or_list: str | list[str], **context) -> str:

12

"""

13

Render a template with the given context.

14

15

Args:

16

template_name_or_list: Template filename or list of template names

17

**context: Template variables

18

19

Returns:

20

Rendered template as string

21

22

Raises:

23

TemplateNotFound: If template file doesn't exist

24

"""

25

26

def render_template_string(source: str, **context) -> str:

27

"""

28

Render a template from a string source.

29

30

Args:

31

source: Template source code as string

32

**context: Template variables

33

34

Returns:

35

Rendered template as string

36

"""

37

38

def stream_template(template_name_or_list: str | list[str], **context) -> Iterator[str]:

39

"""

40

Stream a template as an iterator of strings.

41

42

Args:

43

template_name_or_list: Template filename or list of template names

44

**context: Template variables

45

46

Yields:

47

Template chunks as strings

48

"""

49

50

def stream_template_string(source: str, **context) -> Iterator[str]:

51

"""

52

Stream a template from string source as an iterator.

53

54

Args:

55

source: Template source code as string

56

**context: Template variables

57

58

Yields:

59

Template chunks as strings

60

"""

61

```

62

63

### Template Context Processing

64

65

Decorators and methods for adding variables to template context.

66

67

```python { .api }

68

def context_processor(self, f: Callable) -> Callable:

69

"""

70

Decorator to register a template context processor.

71

72

Args:

73

f: Function that returns dict of context variables

74

75

Returns:

76

The original function

77

"""

78

79

def update_template_context(self, context: dict[str, Any]) -> None:

80

"""

81

Update template context with additional variables.

82

83

Args:

84

context: Context dictionary to update

85

"""

86

```

87

88

### Template Filters

89

90

Functions for registering custom template filters.

91

92

```python { .api }

93

def template_filter(self, name: str | None = None) -> Callable:

94

"""

95

Decorator to register a template filter.

96

97

Args:

98

name: Filter name (defaults to function name)

99

100

Returns:

101

Decorator function

102

"""

103

104

def add_template_filter(self, f: Callable, name: str | None = None) -> None:

105

"""

106

Register a template filter function.

107

108

Args:

109

f: Filter function

110

name: Filter name (defaults to function name)

111

"""

112

```

113

114

### Template Tests

115

116

Functions for registering custom template tests.

117

118

```python { .api }

119

def template_test(self, name: str | None = None) -> Callable:

120

"""

121

Decorator to register a template test.

122

123

Args:

124

name: Test name (defaults to function name)

125

126

Returns:

127

Decorator function

128

"""

129

130

def add_template_test(self, f: Callable, name: str | None = None) -> None:

131

"""

132

Register a template test function.

133

134

Args:

135

f: Test function

136

name: Test name (defaults to function name)

137

"""

138

```

139

140

### Template Globals

141

142

Functions for registering global template functions.

143

144

```python { .api }

145

def template_global(self, name: str | None = None) -> Callable:

146

"""

147

Decorator to register a template global function.

148

149

Args:

150

name: Global name (defaults to function name)

151

152

Returns:

153

Decorator function

154

"""

155

156

def add_template_global(self, f: Callable, name: str | None = None) -> None:

157

"""

158

Register a template global function.

159

160

Args:

161

f: Global function

162

name: Global name (defaults to function name)

163

"""

164

```

165

166

### Template Environment

167

168

Access to the Jinja2 environment for advanced customization.

169

170

```python { .api }

171

class Flask:

172

jinja_env: Environment # Jinja2 environment instance

173

174

def create_jinja_environment(self) -> Environment:

175

"""

176

Create the Jinja2 environment.

177

178

Returns:

179

Configured Jinja2 environment

180

"""

181

182

def select_jinja_autoescape(self, filename: str) -> bool:

183

"""

184

Determine if autoescape should be enabled for a template.

185

186

Args:

187

filename: Template filename

188

189

Returns:

190

True if autoescape should be enabled

191

"""

192

```

193

194

## Usage Examples

195

196

### Basic Template Rendering

197

198

```python

199

from flask import Flask, render_template

200

201

app = Flask(__name__)

202

203

@app.route('/')

204

def home():

205

return render_template('index.html', title='Home Page')

206

207

@app.route('/user/<name>')

208

def user_profile(name):

209

user_data = {

210

'name': name,

211

'email': f'{name}@example.com',

212

'joined': '2023-01-01'

213

}

214

return render_template('user.html', user=user_data)

215

216

@app.route('/posts')

217

def posts():

218

posts = [

219

{'title': 'First Post', 'content': 'Hello World'},

220

{'title': 'Second Post', 'content': 'Flask is great'}

221

]

222

return render_template('posts.html', posts=posts)

223

```

224

225

### Template with Context Variables

226

227

```python

228

from flask import Flask, render_template

229

from datetime import datetime

230

231

app = Flask(__name__)

232

233

@app.route('/dashboard')

234

def dashboard():

235

context = {

236

'user': {

237

'name': 'John Doe',

238

'role': 'admin',

239

'last_login': datetime.now()

240

},

241

'stats': {

242

'total_users': 1250,

243

'active_sessions': 45,

244

'system_status': 'healthy'

245

},

246

'navigation': [

247

{'name': 'Dashboard', 'url': '/dashboard'},

248

{'name': 'Users', 'url': '/users'},

249

{'name': 'Settings', 'url': '/settings'}

250

]

251

}

252

253

return render_template('dashboard.html', **context)

254

```

255

256

### Template Inheritance Example

257

258

Base template (`templates/base.html`):

259

```html

260

<!DOCTYPE html>

261

<html>

262

<head>

263

<title>{% block title %}{% endblock %} - My App</title>

264

<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">

265

</head>

266

<body>

267

<header>

268

<nav>

269

<a href="{{ url_for('home') }}">Home</a>

270

<a href="{{ url_for('about') }}">About</a>

271

</nav>

272

</header>

273

274

<main>

275

{% block content %}{% endblock %}

276

</main>

277

278

<footer>

279

<p>&copy; 2023 My App</p>

280

</footer>

281

</body>

282

</html>

283

```

284

285

Child template (`templates/page.html`):

286

```html

287

{% extends "base.html" %}

288

289

{% block title %}{{ page_title }}{% endblock %}

290

291

{% block content %}

292

<h1>{{ page_title }}</h1>

293

<p>{{ page_content }}</p>

294

{% endblock %}

295

```

296

297

### Custom Template Filters

298

299

```python

300

from flask import Flask, render_template

301

from datetime import datetime

302

303

app = Flask(__name__)

304

305

@app.template_filter('dateformat')

306

def dateformat_filter(value, format='%Y-%m-%d'):

307

"""Format a datetime object."""

308

if value is None:

309

return ''

310

return value.strftime(format)

311

312

@app.template_filter('currency')

313

def currency_filter(value):

314

"""Format a number as currency."""

315

return f'${value:,.2f}'

316

317

# Alternative registration method

318

def reverse_filter(s):

319

"""Reverse a string."""

320

return s[::-1]

321

322

app.add_template_filter(reverse_filter, 'reverse')

323

324

@app.route('/formatted')

325

def formatted_data():

326

data = {

327

'date': datetime.now(),

328

'price': 1234.56,

329

'text': 'Hello World'

330

}

331

return render_template('formatted.html', **data)

332

```

333

334

Template using filters (`templates/formatted.html`):

335

```html

336

<p>Date: {{ date | dateformat('%B %d, %Y') }}</p>

337

<p>Price: {{ price | currency }}</p>

338

<p>Reversed: {{ text | reverse }}</p>

339

```

340

341

### Custom Template Tests

342

343

```python

344

from flask import Flask, render_template

345

346

app = Flask(__name__)

347

348

@app.template_test('even')

349

def is_even(n):

350

"""Test if a number is even."""

351

return n % 2 == 0

352

353

@app.template_test('admin')

354

def is_admin(user):

355

"""Test if user is admin."""

356

return user.get('role') == 'admin'

357

358

@app.route('/users')

359

def users():

360

users = [

361

{'name': 'John', 'role': 'admin', 'id': 1},

362

{'name': 'Jane', 'role': 'user', 'id': 2},

363

{'name': 'Bob', 'role': 'user', 'id': 3}

364

]

365

return render_template('users.html', users=users)

366

```

367

368

Template using tests (`templates/users.html`):

369

```html

370

{% for user in users %}

371

<div class="user {% if user.id is even %}even{% else %}odd{% endif %}">

372

{{ user.name }}

373

{% if user is admin %}

374

<span class="badge">Admin</span>

375

{% endif %}

376

</div>

377

{% endfor %}

378

```

379

380

### Template Globals

381

382

```python

383

from flask import Flask, render_template, url_for

384

import os

385

386

app = Flask(__name__)

387

388

@app.template_global('get_version')

389

def get_version():

390

"""Get application version."""

391

return os.environ.get('APP_VERSION', '1.0.0')

392

393

@app.template_global('active_page')

394

def active_page(page):

395

"""Check if current page is active."""

396

from flask import request

397

return 'active' if request.endpoint == page else ''

398

399

@app.route('/about')

400

def about():

401

return render_template('about.html')

402

```

403

404

Template using globals (`templates/about.html`):

405

```html

406

<p>Version: {{ get_version() }}</p>

407

<nav>

408

<a href="{{ url_for('home') }}" class="{{ active_page('home') }}">Home</a>

409

<a href="{{ url_for('about') }}" class="{{ active_page('about') }}">About</a>

410

</nav>

411

```

412

413

### Context Processors

414

415

```python

416

from flask import Flask, render_template, g

417

from datetime import datetime

418

419

app = Flask(__name__)

420

421

@app.context_processor

422

def inject_globals():

423

"""Inject global variables into all templates."""

424

return {

425

'now': datetime.now(),

426

'app_name': 'My Flask App',

427

'year': datetime.now().year

428

}

429

430

@app.context_processor

431

def inject_user():

432

"""Inject current user into templates."""

433

# In real app, get from session or database

434

user = getattr(g, 'user', None)

435

return {'current_user': user}

436

437

@app.before_request

438

def load_user():

439

# Simulate loading user

440

g.user = {'name': 'John Doe', 'role': 'user'}

441

442

@app.route('/profile')

443

def profile():

444

return render_template('profile.html')

445

```

446

447

Template using context variables (`templates/profile.html`):

448

```html

449

<h1>{{ app_name }}</h1>

450

<p>Welcome, {{ current_user.name }}!</p>

451

<p>Current time: {{ now.strftime('%Y-%m-%d %H:%M:%S') }}</p>

452

<footer>&copy; {{ year }} {{ app_name }}</footer>

453

```

454

455

### Streaming Templates

456

457

```python

458

from flask import Flask, stream_template

459

import time

460

461

app = Flask(__name__)

462

463

@app.route('/stream')

464

def stream_data():

465

def generate_data():

466

"""Generate data for streaming template."""

467

for i in range(10):

468

yield {'index': i, 'data': f'Item {i}'}

469

time.sleep(0.5) # Simulate processing time

470

471

return stream_template('stream.html', items=generate_data())

472

473

@app.route('/large-report')

474

def large_report():

475

# Stream large dataset

476

def get_report_data():

477

# Simulate large dataset

478

for i in range(1000):

479

yield {

480

'id': i,

481

'name': f'Record {i}',

482

'value': i * 10

483

}

484

485

return stream_template('report.html', records=get_report_data())

486

```

487

488

Streaming template (`templates/stream.html`):

489

```html

490

<!DOCTYPE html>

491

<html>

492

<head>

493

<title>Streaming Data</title>

494

</head>

495

<body>

496

<h1>Live Data Stream</h1>

497

<ul>

498

{% for item in items %}

499

<li>{{ item.index }}: {{ item.data }}</li>

500

{% if loop.index % 5 == 0 %}

501

<!-- Flush every 5 items -->

502

{% endif %}

503

{% endfor %}

504

</ul>

505

</body>

506

</html>

507

```

508

509

### Template Security and Escaping

510

511

```python

512

from flask import Flask, render_template_string, Markup

513

514

app = Flask(__name__)

515

516

@app.route('/safe')

517

def safe_content():

518

user_input = '<script>alert("XSS")</script>'

519

safe_html = '<strong>Safe HTML</strong>'

520

521

template = '''

522

<p>User input (escaped): {{ user_input }}</p>

523

<p>Safe HTML (marked safe): {{ safe_html | safe }}</p>

524

<p>Or use Markup: {{ markup_html }}</p>

525

'''

526

527

return render_template_string(

528

template,

529

user_input=user_input,

530

safe_html=safe_html,

531

markup_html=Markup(safe_html)

532

)

533

534

@app.template_filter('safe_html')

535

def safe_html_filter(html):

536

"""Custom filter to mark HTML as safe."""

537

# In real app, sanitize HTML first

538

return Markup(html)

539

```