Django Module 14
Performance and caching interview questions
Interview questions on performance and caching: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between cache_page and the {% cache %} template tag?
cache_page stores a view's whole response, keyed by its address, and returns it without running the view, so it suits pages that are the same for every visitor. {% cache %} stores one part of a template, keyed by a name and any values passed after it, such as the user's id; the view still runs, but whatever inside the fragment would have been computed, such as a lazy queryset, is not.
From the lesson Caching: per-view, fragments, low-level and HTTP
-
Fresher to mid
What does never_cache send, and where do you use it?
Cache-Control: max-age=0, no-cache, no-store, must-revalidate, private, and an Expires header set to the time of the response, so that neither the browser nor any proxy keeps or reuses the page. Use it on pages with personal or sensitive data: account and payment pages, and anything a shared computer should not show the next person.
From the lesson Caching: per-view, fragments, low-level and HTTP
-
Fresher to mid
What does QuerySet.explain() show, and what do you look for first?
Answered in the lesson Django performance: profiling and optimising
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
A developer added cache_page(300) to the residents' dues dashboard to cut database load. The next morning a resident reported seeing another resident's dues. Explain how it happened, contain it, and fix it so the dashboard stays fast.
- What it tests
- How cache_page builds its key, why personal pages leak under it, incident steps for a data exposure, and caching the expensive parts of a personal page safely.
- First step
- Treat it as a data exposure first: remove the cache_page and clear the cache entries of that page at once, so no one else is served a stored copy. Then explain the cause: cache_page keys the response by its address and does not vary by session unless told to.
- Follow-ups
-
- Why did the session middleware's Vary Cookie not prevent it?
- How do you establish who saw what?
- What would you cache instead, and how do you test that it cannot leak?
From the lesson Caching: per-view, fragments, low-level and HTTP
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to staff
The tower dues summary is cached for 10 minutes. Residents who just paid still see the old total, and the committee's monthly closing sometimes shows numbers that do not add up. Design the invalidation, and say what you would never serve from the cache.
- What it tests
- Choosing between timeouts, explicit deletes and versioned keys, deleting on commit, the paths that skip signals, and deciding which reads must not come from a cache.
- First step
- List every way a bill's payment state can change: a save of one bill, a bulk update, an import, the admin, a raw SQL repair. Each must invalidate the tower's summary, and a timeout alone only bounds how long it stays wrong.
- Follow-ups
-
- Why delete on commit rather than at once?
- When would versioned keys be better than deletes?
- What should the monthly closing read?
From the lesson Caching: per-view, fragments, low-level and HTTP
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
The committee's dues report takes 4 seconds for a tower of 1,200 flats and times out for the largest society. Walk through how you find the cause and fix it, and how you show the fix worked.
- What it tests
- Measuring before changing, reading query counts and shapes, choosing the fix that matches the cost, and proving a fix with a repeatable measurement.
- First step
- Measure the report as it is: wrap it in CaptureQueriesContext, or open it with django-debug-toolbar, and count the queries and their shapes. A count that grows with the flats says N+1; a few slow queries say plans and indexes.
- Follow-ups
-
- The report sends 3 queries, but one takes 3.5 seconds. Now what?
- How do you keep it from coming back?
- Would caching the report be a good fix?
From the lesson Django performance: profiling and optimising
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A nightly CSV import of 200,000 water-meter readings takes 40 minutes and sometimes runs out of memory. It reads the file into a list, then calls save() on each reading. What do you change, and what do you check afterwards?
- What it tests
- Batch writes with bulk_create(), streaming reads, transactions for imports, upserts for rows seen before, and what bulk calls skip.
- First step
- Separate the two problems: the time is one statement and one round trip per row, the memory is holding every row and every object at once. Measure both, then fix the writes with batches and the reads with a stream.
- Follow-ups
-
- What does bulk_create() not do that save() did?
- How do you handle readings that were already imported?
- How big should a batch be?
From the lesson Django performance: profiling and optimising
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
After moving to 3 servers with 8 gunicorn workers of 4 threads each, PostgreSQL starts refusing connections at peak hours with "too many clients already". Explain why, size the connections, and choose a fix.
- What it tests
- How Django holds connections per thread, persistent connections against pools, connection budgets across a fleet, and poolers in front of PostgreSQL.
- First step
- Count the connections the fleet can hold at once: Django keeps one per thread, so 3 servers × 8 workers × 4 threads is 96, before cron jobs, task workers, migrations and people. Compare that with max_connections, 100 by default.
- Follow-ups
-
- Would CONN_MAX_AGE = 0 fix it?
- Pool in Django, or PgBouncer in front of the database?
- How do you size the pool?
From the lesson Django performance: profiling and optimising
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes