Claude API Django Integration

Working Django code to integrate the Claude API in 2026. View-based chat handler, streaming responses, session conversation history, and Django REST framework API endpoint patterns.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Django is Python's most widely deployed full-stack web framework. This guide covers every pattern you need to integrate the Claude API into a Django project — from a minimal function-based view to streaming SSE and conversation history.

Installation

pip install anthropic django

Minimal function-based view

# myapp/views.py
import json
import anthropic
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST

# Module-level client — one instance per worker, not per request
client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from env

@csrf_exempt
@require_POST
def chat(request):
    data = json.loads(request.body)
    user_message = data.get("message", "")

    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": user_message}]
    )
    return JsonResponse({"reply": response.content[0].text})
# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("chat/", views.chat, name="chat"),
]

Conversation history with Django sessions

# myapp/views.py
@csrf_exempt
@require_POST
def chat_with_history(request):
    data = json.loads(request.body)
    user_message = data.get("message", "")

    # Load history from session (persists across requests per user)
    history = request.session.get("chat_history", [])
    history.append({"role": "user", "content": user_message})

    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        system="You are a helpful assistant.",
        messages=history,
    )
    assistant_reply = response.content[0].text
    history.append({"role": "assistant", "content": assistant_reply})

    # Keep last 20 turns to stay within context limits
    request.session["chat_history"] = history[-20:]
    return JsonResponse({"reply": assistant_reply})


# Clear conversation
@csrf_exempt
@require_POST
def clear_history(request):
    request.session.pop("chat_history", None)
    return JsonResponse({"status": "cleared"})

Requires SESSION_ENGINE in settings.py (Django's database-backed sessions are the default).

Streaming SSE response

# myapp/views.py
from django.http import StreamingHttpResponse

def stream_chat(request):
    user_message = request.GET.get("message", "Hello")

    def event_stream():
        with client.messages.stream(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=[{"role": "user", "content": user_message}],
        ) as stream:
            for text in stream.text_stream:
                # SSE format: "data: 

"
                yield f"data: {json.dumps({'text': text})}

"
        yield "data: [DONE]

"

    response = StreamingHttpResponse(
        event_stream(),
        content_type="text/event-stream"
    )
    response["Cache-Control"] = "no-cache"
    response["X-Accel-Buffering"] = "no"  # disable Nginx buffering
    return response
<!-- Frontend JavaScript -->
const evtSource = new EventSource(`/chat/stream/?message=${encodeURIComponent(msg)}`);
evtSource.onmessage = (event) => {
  if (event.data === "[DONE]") { evtSource.close(); return; }
  const { text } = JSON.parse(event.data);
  document.getElementById("output").textContent += text;
};

Django REST Framework API view

# pip install djangorestframework
# settings.py: INSTALLED_APPS += ["rest_framework"]

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class ClaudeChatView(APIView):
    def post(self, request):
        user_message = request.data.get("message")
        if not user_message:
            return Response(
                {"error": "message is required"},
                status=status.HTTP_400_BAD_REQUEST
            )
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=[{"role": "user", "content": user_message}],
        )
        return Response({"reply": response.content[0].text})
# myapp/urls.py
from .views import ClaudeChatView
urlpatterns += [path("api/chat/", ClaudeChatView.as_view())]

Django management command for batch processing

# myapp/management/commands/batch_claude.py
from django.core.management.base import BaseCommand
from myapp.models import Article  # your model

class Command(BaseCommand):
    help = "Summarize all unsummarized articles with Claude"

    def handle(self, *args, **options):
        articles = Article.objects.filter(summary="")
        for article in articles:
            response = client.messages.create(
                model="claude-haiku-4-5-20251001",  # cheapest model for bulk
                max_tokens=256,
                messages=[{
                    "role": "user",
                    "content": f"Summarize in 2 sentences: {article.body[:4000]}"
                }]
            )
            article.summary = response.content[0].text
            article.save()
            self.stdout.write(f"Summarized: {article.pk}")

Django vs Flask vs FastAPI for Claude integrations

FrameworkBest forStreaming supportOverhead
DjangoFull web apps with ORM, auth, adminStreamingHttpResponse + SSEHighest — batteries included
FlaskLightweight APIs and microservicesResponse(stream_with_context(...))Minimal — bring your own ORM
FastAPIAsync-first APIs, OpenAPI docs auto-genStreamingResponse + async generatorsMedium — async by default

Use the Claude API Cost Calculator to estimate monthly cost before deploying. For the FastAPI equivalent, see the FastAPI guide. For Flask, see the Flask guide.

Frequently asked questions

How do I use the Claude API in a Django view?
Install `anthropic` with `pip install anthropic`, then instantiate `anthropic.Anthropic()` at module level (not per-request) in your view file. Call `client.messages.create()` inside the view function and return `JsonResponse({'reply': message.content[0].text})`.
How do I stream Claude responses in Django?
Use `StreamingHttpResponse` with a generator function that calls `client.messages.stream()` and yields each `text` delta as Server-Sent Events (SSE). Set `content_type='text/event-stream'` and add `X-Accel-Buffering: no` header to disable Nginx buffering.
Should I use Django REST framework or plain Django views for a Claude chatbot?
Plain Django views are simpler for a basic chatbot. Use Django REST Framework (DRF) if you need serialization, throttling, or a browsable API — DRF's `APIView` works identically to a plain view for calling Claude.
How do I store conversation history in Django sessions?
Use `request.session` to store the message list between requests: `history = request.session.get('history', [])`, append user+assistant turns, then `request.session['history'] = history`. Django session middleware serializes this to the session backend automatically.
Where should I store the Anthropic API key in a Django project?
Store it in environment variables and read it with `os.environ.get('ANTHROPIC_API_KEY')` in `settings.py`. Use `python-decouple` or `django-environ` to load from a `.env` file locally; in production, inject via your hosting platform's environment configuration.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript