Django HTTP Methods
A normal link may be followed by a browser, crawler or preview service. GET should read state, while an intentional change uses an appropriate checked method.
How it works
The reservation view combines login_required with require_POST. An authenticated GET therefore receives 405 instead of changing the database. Anonymous callers are sent to login before reaching the method check because of decorator order. Decide which checks should run first and test the public behaviour. A confirmation screen may use GET to explain the action, but the final mutation still needs a protected POST.
Run in the supplied local Django project
This lesson uses Django 5.2.18 LTS with Python 3.12. Download the source downloader and run node download-project.mjs http://127.0.0.1:8000 with Node 22 while previewing locally. It creates a new bhylu-django-lab folder and refuses to overwrite an existing one. After deployment, the default base is bhylu.com; until then use your local preview URL.
Inside that new folder, create a virtual environment, install requirements.txt and run the complete lesson file shown below. Every lesson creates a fresh in-memory SQLite database and temporary upload storage. It does not edit the interactive lab’s db.sqlite3 or Bhylu’s database. The visible listing below is the lesson’s core code; its complete downloaded file includes the shared bootstrap.
Django does not run in Bhylu’s current browser playground. No Apache, MySQL or global PHP configuration change is needed. See the setup lesson for the full project and commands.
Example
Run .venv\Scripts\python.exe lessons\request-methods.py from the downloaded project root. Download the complete lesson file; keep it under lessons/. The project’s shared models, forms, views and fixture are prerequisites, not a hidden online runtime.
from django.contrib.auth import get_user_model
client = Client()
client.force_login(get_user_model().objects.get(username="alex"))
response = client.get("/workshops/lamp-care/book/")
print(response.status_code)
print(response.headers["Allow"])
print(Reservation.objects.count())
Expected result
405 POST 0
The endpoint advertises POST as the accepted method and the database remains unchanged. Checking the row count prevents a misleading test that verifies only the status after an unintended write.
Use Django’s versioned official documentation for exact API contracts and the deployment checklist before a separate release.