Blade Templates
๐ฒ Blade Templates
view() from the last chapter needs an actual template file. Blade is Laravel's templating engine โ same job as the Django Template Language, different punctuation: @if instead of {% if %}, and directives compiled straight down to plain PHP rather than DTL's intentionally restricted mini-language.
Where Blade Views Live
Every Blade file lives in resources/views/, with dot notation mapping to nested folders โ a flatter convention than Django's app-namespaced templates/appname/ directories:
resources/views/ โโโ layouts/ โ โโโ app.blade.php โโโ books/ โ โโโ index.blade.php โ โโโ show.blade.php
// In a controller (Chapter 3): return view('books.index', ['books' => Book::all()]); // 'books.index' -> resources/views/books/index.blade.php
๐ค Variables & Echoing
{{ }} auto-escapes by default โ the same XSS defense Django's {{ }} provides, just with curly braces instead of DTL's own:
<h1>{{ $book->title }}</h1>
// If $book->title contains <script>, this renders as inert text,
// not an executable script tag โ identical protection to Django's auto-escaping.
{!! !!} is Blade's equivalent of Django's |safe filter โ it opts out of escaping entirely:
{!! $book->trusted_html_description !!}
// โ ๏ธ NEVER on unsanitized user input โ same warning as Django's |safe,
// direct callback to the XSS course
Control Structures
@if ($books->isEmpty()) <p>No books yet.</p> @else <ul> @foreach ($books as $book) <li>{{ $loop->iteration }}. {{ $book->title }}</li> @endforeach </ul> @endif
$loop is Blade's automatic loop variable โ $loop->iteration, $loop->first, $loop->last โ the direct equivalent of Django's forloop.counter and friends, available inside any @foreach without being passed in from the controller.
Django Template Language vs Blade โ Same Job, Different Punctuation
Django Template Language
{% if books %}
{% for book in books %}
{{ book.title|upper }}
{% endfor %}
{% else %}
No books.
{% endif %}
Blade
@if($books->isNotEmpty()) @foreach($books as $book) {{ strtoupper($book->title) }} @endforeach @else No books. @endif
๐งฉ Template Inheritance
Blade's version of extends/block uses @extends/@section/@yield instead:
A Layout and a Child View
<!-- resources/views/layouts/app.blade.php --> <!DOCTYPE html> <html> <head> <title>@yield('title', 'My Library')</title> </head> <body> <nav>Home | Books</nav> @yield('content') <footer>© 2026</footer> </body> </html> <!-- resources/views/books/index.blade.php --> @extends('layouts.app') @section('title', 'All Books') @section('content') <ul> @foreach ($books as $book) <li>{{ $book->title }}</li> @endforeach </ul> @endsection
@yield vs @section/@endsection
The layout declares a placeholder with @yield; a child view fills it with @section/@endsection โ Django's {% block %} plays both roles in one tag, Blade splits it into two.
@include
Pulls in a reusable partial inline โ @include('books.book-card') โ the same job as Django's {% include %}.
A Real Philosophical Difference
Course 1's Django Templates chapter emphasized DTL's deliberate restriction โ no method calls with arguments, no arbitrary Python. Blade takes the opposite stance: it compiles directly to plain PHP, so @php blocks (and even calling PHP functions inline, as strtoupper($book->title) did above) are fully available:
@php $discountedPrice = $book->price * 0.9; @endphp <p>Sale price: {{ number_format($discountedPrice, 2) }}</p>
This is genuinely more powerful and genuinely easier to misuse โ DTL's restriction exists specifically to keep business logic out of templates; Blade trusts the developer to maintain that discipline manually.
๐ป Coding Challenges
Challenge 1: Render a List With Blade
Write a Blade view that loops over a $books variable, printing each title using $loop->iteration for numbering, with a fallback message if the collection is empty.
Goal: Practice @if/@foreach together with the $loop variable.
Challenge 2: Build a Layout + Two Child Views
Write a layouts/app.blade.php with @yield('title') and @yield('content'), then two child views (books/index.blade.php and books/show.blade.php) that each @extends it with different content.
Goal: Practice the @extends/@section/@yield inheritance pattern across more than one page.
Challenge 3: Demonstrate Escaping
Pass a string containing <script> tags into a Blade view, render it two ways โ once as {{ $value }} and once as {!! $value !!} โ and explain what each one actually sends to the browser.
Goal: Practice recognizing Blade's auto-escaping in action, the same way Django's Templates chapter did for DTL.
{!! !!} on User InputThe exact same warning from Django's |safe filter applies here, just with Blade's syntax: {!! $comment->text !!} on anything that ultimately traces back to user input is a direct XSS vulnerability, since it disables the one built-in protection Blade provides by default. Reserve {!! !!} for content that's already been through a real sanitization step โ never as a quick fix for an escaping-related rendering issue.
๐ฏ What's Next
Views can now display data โ the next chapter covers where that data actually comes from: Eloquent ORM, defining models, migrations, and querying with Eloquent's query builder compared to Django's ORM.