Build an AI Chatbot with Django
Part 4 built the real integration foundation — a service module and a persistence model. This part completes it into a genuine, working Django chatbot app, following the same real app structure the Django From Scratch series established.
The real, complete app structure
support/
├── models.py → part 4's ChatMessage model
├── services.py → part 4's ask_support_assistant()
├── views.py
├── urls.py
└── templates/
└── support/
└── chat.htmlReal, proper URL configuration
# support/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("support/", views.chat_view, name="support-chat"),
]# project/urls.py
from django.urls import path, include
urlpatterns = [
path("", include("support.urls")),
]This is the exact real URL pattern from the Django series' own URLs coverage — nothing AI-specific here, deliberately, since the routing layer doesn't need to know or care that this particular view happens to call an LLM.
The real, complete view, extending part 4's minimal version
# support/views.py
from django.shortcuts import render
from django.contrib.sessions.backends.db import SessionStore
from .services import ask_support_assistant
from .models import ChatMessage
PLAN_DATA = """
- Gift Subscription: $18/mo, 1 bag, free shipping
- Monthly Subscription: $16/mo, 1 bag, free shipping
"""
def chat_view(request):
if not request.session.session_key:
request.session.create()
session_id = request.session.session_key
if request.method == "POST":
question = request.POST.get("message", "").strip()
if question:
ChatMessage.objects.create(session_id=session_id, role="user", content=question)
answer = ask_support_assistant(question, PLAN_DATA)
ChatMessage.objects.create(session_id=session_id, role="assistant", content=answer)
messages = ChatMessage.objects.filter(session_id=session_id)
return render(request, "support/chat.html", {"messages": messages})request.session.create() ensures a real, persistent session key exists even for a brand-new visitor — directly resolving part 4's minimal version, which assumed a session key already existed.
The real, complete template
<!-- support/templates/support/chat.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bright Leaf Coffee Support</title>
</head>
<body>
<main>
<h1>Ask us anything</h1>
<div>
{% for message in messages %}
<p><strong>{{ message.role }}:</strong> {{ message.content }}</p>
{% endfor %}
</div>
<form method="POST">
{% csrf_token %}
<label for="message">Your question</label>
<input type="text" id="message" name="message" required />
<button type="submit">Send</button>
</form>
</main>
</body>
</html>{% csrf_token %} is genuinely required here — exactly the same CSRF protection the Django series' own forms and CSRF coverage covers, and it applies identically to an AI-powered form as to any other real Django POST request; the AI logic behind the view changes nothing about Django's own security requirements.
This is genuinely why part 4 built a separate services module first — the view above is almost entirely real, standard Django (sessions, ORM queries, template rendering) with exactly one line, ask_support_assistant(...), actually touching AI logic. A developer who's never worked with an LLM API can read and maintain this entire view correctly.
Why database-backed history is a real, meaningful upgrade from part 3's Flask version
Flask (part 3): conversation lived in a browser cookie — gone if
cleared, invisible server-side, size-constrained
Django (this part): conversation lives in a real database table —
survives across devices for a logged-in real user (once tied to a
real user account instead of just a session), inspectable for
real support quality review, with no practical size constraintThis is a genuine, structural improvement, not just a different framework doing the same thing — persistent, queryable conversation history is what makes a real feature like "show me my last support conversation" or "flag conversations where the assistant said it didn't know the answer" actually buildable.
Next: building a real AI REST API with FastAPI — a genuinely different, API-first pattern for when the AI feature needs to serve other real applications, not render its own HTML.