Premier League Predictor: Django & MySQL — Chapter 4, Exercise 2 ==================================================== TASK Explain why @ensure_csrf_cookie is needed on fixture_entry even though that view renders no traditional HTML form, and what would happen to the Add Fixture button's own fetch call if the X-CSRFToken header were left out entirely. SOLUTION Django normally sets its CSRF cookie as a side effect of rendering the {% csrf_token %} template tag inside a real HTML
— the tag calls get_token(request) internally, which is what actually causes the cookie to be set on the response. fixture_entry.html has no traditional at all; every state-changing action on this page happens through a JavaScript fetch() call instead, so there's no {% csrf_token %} tag anywhere to trigger that cookie being set through the normal path. @ensure_csrf_cookie exists specifically for pages shaped like this one: it forces the CSRF cookie to be set on the response regardless of whether any {% csrf_token %} tag actually appears in the rendered template. Without it, a first-time visitor to this page might receive a response with no csrftoken cookie at all, meaning getCookie('csrftoken') in fixtures.js would return undefined, and the X-CSRFToken header sent with the addFixture() request would end up either missing its real value or containing "undefined" as a literal string — either way, not a real, valid CSRF token. If the X-CSRFToken header were left out of the fetch call entirely (or sent with an invalid value), Django's CsrfViewMiddleware — active by default — would reject the POST request to create_fixture before the view's own code runs at all, returning a real 403 Forbidden response. This is a completely different failure from the 409 the same route returns for a genuine duplicate team: the 403 happens at the middleware layer, before create_fixture's own logic (the home_team_id == away_team_id check, the used_team_ids query) ever executes, while the 409 is create_fixture's own deliberate business logic response after successfully passing CSRF validation. WHY THIS WORKS AS AN ANSWER ---------------------------- It explains precisely why the normal CSRF-cookie-setting mechanism ({% csrf_token %} inside a form) doesn't apply to this particular page, states what @ensure_csrf_cookie does instead, and correctly distinguishes the real 403 CSRF failure (a middleware-level rejection, before the view runs) from the 409 duplicate-team failure (a deliberate response from inside the view's own logic).