~/TechPurAI
~/tutorials/ai-projects-with-python/integrating-an-llm-api-into-a-django-project
intermediate·part 4 of 22·3 min read

Integrate an LLM API into a Django Project

Updated Aug 16, 2026Python · AI

Flask's minimal structure from part 3 worked for a small demo, but a real Django project — like the one the Django From Scratch series built — needs a genuinely different, more structured integration pattern. This part covers it correctly, as the foundation every remaining Django part in this series builds on.

Real, practical setup

bash
pip install anthropic python-dotenv django-environ

django-environ is a real, widely used package for reading environment variables into Django settings cleanly — a genuine, Django-idiomatic alternative to python-dotenv used directly, fitting the Django series' own settings conventions.

Real, correct settings configuration

python
# settings.py
import environ

env = environ.Env()
environ.Env.read_env()

ANTHROPIC_API_KEY = env("ANTHROPIC_API_KEY")
text
# .env (never committed, exactly per this series' part 1 discipline)
ANTHROPIC_API_KEY=your-real-api-key-here

Storing the real key in settings.py, read from the environment, is the genuinely correct Django-idiomatic location — every real Django app can then reference settings.ANTHROPIC_API_KEY, rather than each individual view or module independently reading environment variables.

A real, separate service module — not AI logic inside a view

python
# support/services.py
from anthropic import Anthropic
from django.conf import settings

def get_client() -> Anthropic:
    return Anthropic(api_key=settings.ANTHROPIC_API_KEY)

def ask_support_assistant(user_question: str, plan_data: str) -> str:
    client = get_client()
    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        system=(
            f"You are a customer support assistant for Bright Leaf "
            f"Coffee. Real, current plan data:\n{plan_data}\nOnly "
            f"answer using this real data."
        ),
        messages=[{"role": "user", "content": user_question}],
    )
    return response.content[0].text

This real, separate services.py module — a genuine, standard Django pattern for business logic that doesn't belong directly in a view or model — is what keeps a real view (built in part 5) thin and focused on handling the actual HTTP request/response cycle, exactly the same separation-of-concerns discipline the Django REST Framework series' own serializer and view separation already established.

Why it matters

Putting AI logic directly inside a real Django view — rather than in a separate service module — genuinely works for a first, small prototype, but it becomes a real, practical problem the moment the same AI logic needs to be reused from a second view, a management command, or a Celery background task. A real service module is callable from any of those contexts identically; logic embedded in one specific view is not.

A real, minimal model for storing conversation history

python
# support/models.py
from django.db import models

class ChatMessage(models.Model):
    session_id = models.CharField(max_length=64)
    role = models.CharField(max_length=20)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["created_at"]

This directly resolves part 3's honest limitation — rather than storing conversation history in a browser cookie via Flask's session, a real Django model persists it in the actual database, exactly the durable storage pattern the Django series' own models coverage established, and genuinely necessary once a conversation needs to survive longer than a single browser session or be inspected server-side.

A real, minimal, working view using this integration

python
# support/views.py
from django.shortcuts import render
from .services import ask_support_assistant
from .models import ChatMessage

PLAN_DATA = "- Gift Subscription: $18/mo\n- Monthly Subscription: $16/mo"

def chat_view(request):
    if request.method == "POST":
        question = request.POST["message"]
        answer = ask_support_assistant(question, PLAN_DATA)
        ChatMessage.objects.create(session_id=request.session.session_key, role="user", content=question)
        ChatMessage.objects.create(session_id=request.session.session_key, role="assistant", content=answer)

    messages = ChatMessage.objects.filter(session_id=request.session.session_key)
    return render(request, "support/chat.html", {"messages": messages})

This is a genuine, minimal working integration — part 5 builds directly on this exact services.py and models.py, adding a real, complete chatbot UI, proper session handling, and the production concerns this intentionally minimal version leaves out.

Next: building a real, complete AI chatbot with Django — the full application built directly on this part's integration foundation.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous3. Adding a Simple Web UI to Your Python Chatbotnext →5. Build an AI Chatbot with Django