Rendering and CSRF
The token is not optional. Every form that POSTs needs {% csrf_token %} inside it. Without it, the submission is rejected with a 403.
It is the single most common Django form error, and the message is clear once you have seen it once. The token proves the request came from your own page rather than from a different site quietly submitting on a signed-in person's behalf.
GET forms do not need it, because a GET should not change anything.
Rendering field by field. {{ form.as_p }} is fine for a first draft and gives you no control over the markup.
Once accessibility matters, and it should, render each field yourself: a real <label> tied to the input with for and id, the field's errors next to it rather than only at the top, and aria-describedby linking help text. Django exposes form.title.id_for_label and form.title.errors precisely so you can do this.
Mark this lesson complete
Signed in, your progress follows you to every device.