Caching
⚡ Caching
Cache facade is the closest 1:1 parallel this whole comparison has found: Cache::remember() and Django's cache.get_or_set() are nearly identical in shape. But this chapter also has real gaps worth being honest about — Django's core ships more caching machinery than Laravel does.
Cache Stores
// config/cache.php 'default' => env('CACHE_STORE', 'database'),
redis / memcached
Real production stores — the same role Redis/Memcached play for Django's CACHES setting.
array: Testing Only
Stores cached values only in memory for the current process — never persists across separate requests, directly parallel to Django's DummyCache in intent, though array actually caches within one process rather than always missing.
🔑 The Cache Facade
use Illuminate\Support\Facades\Cache; Cache::put('featured_book_count', 42, 300); // cache for 300 seconds Cache::get('featured_book_count'); // 42 — or null if expired/missing Cache::forget('featured_book_count'); // explicit invalidation
Cache::remember(): The Closest 1:1 Parallel Yet
Django's get_or_set() vs Laravel's remember()
Django
stats = cache.get_or_set(
"book_stats",
compute_stats,
timeout=600
)
Laravel
$stats = Cache::remember( 'book_stats', 600, fn() => Book::query()->selectRaw('AVG(price) as avg_price, COUNT(*) as total')->first() );
Same three arguments in almost the same order — key, timeout (position differs), and a callback that only runs on a cache miss. Of every comparison in this whole project, this pairing is about as close as two frameworks get.
🕳️ Where Django's Core Actually Has More
Two honest gaps, not advantages — worth stating plainly rather than always finding a Laravel win:
No Built-in @cache_page Equivalent
Django's @cache_page decorator caches an entire view's response in one line. Laravel core has no direct equivalent — full-response caching typically needs a package (e.g. spatie/laravel-responsecache) or manually wrapping a controller method's return value in Cache::remember() yourself.
No Built-in {% cache %} Equivalent
Django's {% cache %} template tag caches a template fragment directly. Blade has no core directive for this — the same pattern is achieved by wrapping the relevant data (not the rendered HTML) in Cache::remember() before passing it to the view.
// The Laravel-native way to approximate Django's @cache_page for one controller method: public function index() { $books = Cache::remember('books.index', 900, fn() => Book::all()); return view('books.index', ['books' => $books]); } // Caches the DATA, not the rendered response — close, but not identical to // Django's whole-response caching, which also skips re-rendering the template.
Cache Invalidation via Model Events
The exact same signal-based invalidation pattern from Django's caching chapter, using the Eloquent model events from Chapter 4:
Invalidating on Save/Delete
// app/Models/Book.php use Illuminate\Support\Facades\Cache; protected static function booted(): void { static::saved(fn() => Cache::forget('book_stats')); static::deleted(fn() => Cache::forget('book_stats')); }
Remember Chapter 4's gotcha: these model events fire on every save, including factories and seeders — for cache invalidation specifically, that's actually fine (clearing a cache entry too often is harmless, unlike sending an unwanted email), so model events are a reasonable choice here even though they weren't for side effects like emails.
💻 Coding Challenges
Challenge 1: Cache an Expensive Query
Write a controller method that caches the count and average price of all books under the key book_stats for 10 minutes using Cache::remember().
Goal: Practice the Cache::remember() pattern, the closest parallel to Django's get_or_set() in this course.
Challenge 2: Approximate Full-Response Caching
Write a controller method that caches the entire book list data for 15 minutes, and explain in one sentence how this differs from Django's @cache_page, which caches the full rendered response instead of just the data.
Goal: Practice recognizing the gap between Laravel's data-level caching and Django's response-level caching.
Challenge 3: Invalidate the Cache on Save
Add a booted() method to the Book model that clears the book_stats cache key whenever a book is saved or deleted, and explain why this is a safe use of an automatic model event, unlike Chapter 4's welcome-email trap.
Goal: Practice cache invalidation via model events, and articulate why this particular side effect is safe to run on every save.
The same warning from Django's caching chapter applies word-for-word here: forgetting to call Cache::forget() (or not tying it to the right model event) means stale data persists until the timeout expires, with no error indicating anything is wrong — it just quietly shows outdated numbers. Separately, a Laravel-specific trap: the array cache driver only persists within a single process/request lifecycle — using it in a test to verify caching behavior across what should be two separate requests will misleadingly appear to "not cache at all," when really the driver was never meant to persist across process boundaries in the first place.
🎯 What's Next
With expensive data cached correctly, the next chapter covers a different kind of protection: Authorization — Laravel's Policies and Gates, compared to Django's built-in permission system.