Django und Python Interviewfragen: Die Top 25 in 2026
Die 25 haeufigsten Django- und Python-Interviewfragen. ORM, Views, Middleware, DRF, Signals und Optimierung mit ausfuehrlichen Antworten und Codebeispielen.

Django-Vorstellungsgespraeche pruefen die Kompetenz im Umgang mit Pythons beliebtestem Web-Framework, das Verstaendnis des ORM, der MVT-Architektur und die Faehigkeit, robuste REST-APIs zu entwickeln. Dieser Leitfaden behandelt die 25 am haeufigsten gestellten Fragen, von Django-Grundlagen bis hin zu fortgeschrittenen Django REST Framework Patterns.
Interviewer schaetzen Kandidaten, die Djangos architektonische Entscheidungen erlaeutern koennen. Das Verstaendnis, warum das Framework bestimmte Konventionen verfolgt (Convention over Configuration), macht in Vorstellungsgespraechen einen echten Unterschied.
Django-Grundlagen
Frage 1: Beschreiben Sie die MVT-Architektur von Django
Die Model-View-Template (MVT)-Architektur ist Djangos Variante des MVC-Musters. Das Framework uebernimmt den Controller-Teil automatisch, was die Entwicklung vereinfacht.
# models.py
# The Model represents data structure and business logic
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_at = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
"auth.User",
on_delete=models.CASCADE, # Deletes articles when author is deleted
related_name="articles" # Reverse access: user.articles.all()
)
class Meta:
ordering = ["-published_at"] # Default ordering
def __str__(self):
return self.title# views.py
# The View contains request processing logic
from django.shortcuts import render, get_object_or_404
def article_detail(request, pk):
# get_object_or_404 raises Http404 if the object doesn't exist
article = get_object_or_404(Article, pk=pk)
return render(request, "blog/article_detail.html", {"article": article})Im MVT-Muster fungiert Django als Controller, indem es URLs ueber urls.py an die entsprechenden Views weiterleitet. Das Template uebernimmt die HTML-Darstellung.
Frage 2: Was ist der Unterschied zwischen einem Django-Projekt und einer App?
Ein Projekt ist die uebergeordnete Konfiguration (Einstellungen, Root-URLs, WSGI/ASGI). Eine App ist ein wiederverwendbares Modul mit einer einzelnen Verantwortung. Ein Projekt enthaelt mehrere Apps.
# Creating a project and an app
# django-admin startproject myproject
# python manage.py startapp blog
# settings.py
# Registering apps in the project
INSTALLED_APPS = [
"django.contrib.admin", # Admin interface
"django.contrib.auth", # Authentication
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Custom apps
"blog.apps.BlogConfig", # Blog app
"users.apps.UsersConfig", # Users app
]Jede App folgt dem Single-Responsibility-Prinzip und kann in verschiedenen Projekten wiederverwendet werden.
Frage 3: Erklaeren Sie den Django Request Lifecycle
Die Anfrage durchlaeuft mehrere Schichten, bevor sie die View erreicht. Das Verstaendnis dieses Zyklus ist fuer Debugging und Optimierung unerlaesslich.
# middleware.py
# Middlewares intercept every request/response
class RequestTimingMiddleware:
"""Middleware that measures processing time."""
def __init__(self, get_response):
self.get_response = get_response # Reference to the next middleware
def __call__(self, request):
import time
start = time.time()
# Request phase: before the view
response = self.get_response(request)
# Response phase: after the view
duration = time.time() - start
response["X-Request-Duration"] = f"{duration:.3f}s"
return responseDer vollstaendige Zyklus: HTTP-Anfrage → WSGI/ASGI → Middlewares (process_request) → URL-Resolver → View → Middlewares (process_response) → HTTP-Antwort.
ORM und Datenbank
Frage 4: Wie funktionieren Djangos QuerySets und was ist Lazy Loading?
QuerySets werden lazy ausgewertet: Es wird keine SQL-Abfrage ausgefuehrt, bis die Daten tatsaechlich verwendet werden.
# queryset_lazy.py
# Demonstrating QuerySet lazy loading
# No SQL query executed here
qs = Article.objects.filter(published=True) # No query
qs = qs.exclude(title="Draft") # Still none
qs = qs.order_by("-created_at") # Still none
# The SQL query runs ONLY here
for article in qs: # ONE combined SQL query
print(article.title)
# Other evaluation triggers
list(qs) # Converting to list
qs[0] # Index access
len(qs) # Counting (prefer qs.count())
bool(qs) # Existence check (prefer qs.exists())Diese verzogerte Auswertung ermoeglicht das Verketten von Filtern ohne Overhead, wobei nur eine optimierte Abfrage ausgefuehrt wird.
Frage 5: Was ist das N+1-Problem und wie loest man es?
Das N+1-Problem tritt auf, wenn eine Hauptabfrage N zusaetzliche Abfragen zum Laden von Beziehungen generiert. Es ist die haeufigste Ursache fuer Langsamkeit in Django-Anwendungen.
# n_plus_one.py
# N+1 problem and solutions
# ❌ PROBLEM: N+1 queries
# 1 query for articles + 1 query PER article for the author
articles = Article.objects.all()
for article in articles:
print(article.author.username) # SQL query on every iteration!
# ✅ SOLUTION 1: select_related (ForeignKey, OneToOne)
# Joins tables in ONE SQL query (JOIN)
articles = Article.objects.select_related("author").all()
for article in articles:
print(article.author.username) # No additional query
# ✅ SOLUTION 2: prefetch_related (ManyToMany, reverse FK)
# Executes 2 separate queries + Python assembly
articles = Article.objects.prefetch_related("tags").all()
for article in articles:
print(article.tags.all()) # Data already cached
# ✅ SOLUTION 3: Custom Prefetch with filtering
from django.db.models import Prefetch
articles = Article.objects.prefetch_related(
Prefetch(
"comments",
queryset=Comment.objects.filter(approved=True).select_related("user"),
to_attr="approved_comments" # Custom attribute
)
)select_related wird fuer ForeignKey/OneToOne-Beziehungen (SQL JOIN) verwendet und prefetch_related fuer ManyToMany- oder umgekehrte Beziehungen (separate Abfragen).
Frage 6: Wie erstellt man einen Custom Manager und wann setzt man ihn ein?
Custom Manager kapseln haeufige Abfragen auf Modellebene und machen den Code lesbarer und wiederverwendbarer.
# managers.py
# Custom Managers and QuerySets
class PublishedQuerySet(models.QuerySet):
"""Reusable QuerySet for published articles."""
def published(self):
return self.filter(status="published", published_at__lte=timezone.now())
def by_author(self, user):
return self.filter(author=user)
def popular(self):
return self.annotate(
comment_count=models.Count("comments")
).order_by("-comment_count")
class PublishedManager(models.Manager):
"""Manager that exposes only published articles."""
def get_queryset(self):
return PublishedQuerySet(self.model, using=self._db).published()
class Article(models.Model):
# ...
objects = models.Manager() # Default manager (all articles)
published = PublishedManager() # Custom manager (published only)
# Usage:
# Article.objects.all() → All articles
# Article.published.all() → Published articles only
# Article.published.popular() → Published articles sorted by popularityCustom Manager folgen dem DRY-Prinzip und zentralisieren die Abfragelogik.
Bereit für deine Django-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Views und URLs
Frage 7: Wann verwendet man Class-Based Views vs Function-Based Views?
Function-Based Views (FBVs) bieten Einfachheit und explizite Kontrolle. Class-Based Views (CBVs) bringen Wiederverwendbarkeit und Struktur durch Vererbung.
# views_comparison.py
# FBV: Explicit, simple, easy to understand
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def article_list(request):
if request.method == "GET":
articles = Article.published.all()
return render(request, "articles/list.html", {"articles": articles})
# POST: article creation
form = ArticleForm(request.POST)
if form.is_valid():
form.save()
return redirect("article-list")
return render(request, "articles/list.html", {"form": form})# views_cbv.py
# CBV: Reusable, extensible via mixins
from django.views.generic import ListView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = "articles/list.html"
context_object_name = "articles" # Variable name in the template
paginate_by = 20 # Automatic pagination
def get_queryset(self):
# Override to filter published articles
return Article.published.all()
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
form_class = ArticleForm
success_url = reverse_lazy("article-list")
def form_valid(self, form):
form.instance.author = self.request.user # Assign the author
return super().form_valid(form)Praktische Regel: FBVs fuer einfache oder nicht-standardmaessige Logik verwenden, CBVs fuer Standard-CRUD-Operationen.
Frage 8: Wie funktionieren Middlewares in Django?
Middlewares sind Hooks, die jede Anfrage/Antwort verarbeiten. Jede Middleware kann in verschiedenen Phasen des Verarbeitungszyklus eingreifen.
# auth_middleware.py
# Custom authentication middleware
import jwt
from django.conf import settings
from django.http import JsonResponse
class JWTAuthenticationMiddleware:
"""Verifies JWT token on protected endpoints."""
EXEMPT_PATHS = ["/api/auth/login", "/api/auth/register", "/health"]
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Skip exempt paths
if any(request.path.startswith(p) for p in self.EXEMPT_PATHS):
return self.get_response(request)
# Extract and verify the token
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
return JsonResponse({"error": "Missing token"}, status=401)
try:
token = auth_header.split(" ")[1]
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
request.user_id = payload["user_id"] # Attach to request
except jwt.ExpiredSignatureError:
return JsonResponse({"error": "Token expired"}, status=401)
except jwt.InvalidTokenError:
return JsonResponse({"error": "Invalid token"}, status=401)
return self.get_response(request)Die Reihenfolge der Middlewares in MIDDLEWARE ist entscheidend: Sie werden von oben nach unten fuer Anfragen und von unten nach oben fuer Antworten ausgefuehrt.
Django REST Framework
Frage 9: Was ist der Unterschied zwischen Serializer und ModelSerializer?
Serializer definiert jedes Feld manuell, waehrend ModelSerializer Felder automatisch aus dem Modell generiert.
# serializers.py
from rest_framework import serializers
# Manual Serializer: full control over each field
class ArticleSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=200)
content = serializers.CharField()
author_name = serializers.SerializerMethodField()
def get_author_name(self, obj):
return obj.author.get_full_name()
def create(self, validated_data):
return Article.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.title = validated_data.get("title", instance.title)
instance.content = validated_data.get("content", instance.content)
instance.save()
return instance
# ModelSerializer: automatic field generation
class ArticleModelSerializer(serializers.ModelSerializer):
author_name = serializers.SerializerMethodField()
comment_count = serializers.IntegerField(read_only=True)
class Meta:
model = Article
fields = ["id", "title", "content", "author", "author_name",
"comment_count", "published_at"]
read_only_fields = ["published_at"]
def get_author_name(self, obj):
return obj.author.get_full_name()ModelSerializer wird fuer Standardfaelle bevorzugt und Serializer, wenn sich die Darstellung wesentlich vom Modell unterscheidet.
Frage 10: Wie implementiert man Pagination in DRF?
DRF bietet verschiedene Paginierungsstrategien, die global oder pro View konfigurierbar sind.
# settings.py
# Global pagination configuration
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}
# pagination.py
# Custom pagination per view
from rest_framework.pagination import CursorPagination, LimitOffsetPagination
class ArticleCursorPagination(CursorPagination):
"""Cursor pagination: performant for large datasets."""
page_size = 20
ordering = "-published_at" # Indexed field required
cursor_query_param = "cursor"
class ArticleLimitOffsetPagination(LimitOffsetPagination):
"""Offset/limit pagination: flexible but less performant."""
default_limit = 20
max_limit = 100
# views.py
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.published.all()
serializer_class = ArticleModelSerializer
pagination_class = ArticleCursorPagination # View-specific paginationCursor-Paginierung wird fuer grosse Datensaetze empfohlen, da sie unabhaengig von der Seitennummer performant bleibt, im Gegensatz zu OFFSET/LIMIT.
Frage 11: Wie sichert man eine API mit DRF-Berechtigungen?
DRF bietet ein modulares Berechtigungssystem, das Authentifizierung und granulare Autorisierung kombiniert.
# permissions.py
from rest_framework.permissions import BasePermission, IsAuthenticated
class IsAuthorOrReadOnly(BasePermission):
"""Only the author can modify, everyone can read."""
def has_object_permission(self, request, view, obj):
# GET, HEAD, OPTIONS are always allowed
if request.method in ("GET", "HEAD", "OPTIONS"):
return True
# Only the author can modify or delete
return obj.author == request.user
class IsAdminOrManager(BasePermission):
"""Access restricted to admins and managers."""
def has_permission(self, request, view):
return (
request.user.is_authenticated
and request.user.role in ("admin", "manager")
)
# views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.throttling import UserRateThrottle
class ArticleViewSet(ModelViewSet):
permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
throttle_classes = [UserRateThrottle] # Rate limiting
def get_permissions(self):
# Dynamic permissions based on action
if self.action == "destroy":
return [IsAdminOrManager()]
return super().get_permissions()permission_classes werden auf View-Ebene kombiniert und has_object_permission fuer feingranulare Objektkontrolle.
Signals und asynchrone Aufgaben
Frage 12: Wie funktionieren Django Signals und wann setzt man sie ein?
Signals ermoeglichen die Entkopplung von Komponenten, indem sie auf Ereignisse des Frameworks oder der Anwendung reagieren.
# signals.py
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django.core.mail import send_mail
@receiver(post_save, sender=Article)
def notify_on_publish(sender, instance, created, **kwargs):
"""Sends a notification when an article is published."""
if not created and instance.status == "published":
# Triggered only on publication (not creation)
subscribers = instance.author.subscribers.values_list("email", flat=True)
send_mail(
subject=f"New article: {instance.title}",
message=f"Check out the latest article by {instance.author.username}",
from_email="noreply@example.com",
recipient_list=list(subscribers),
)
@receiver(pre_delete, sender=Article)
def cleanup_article_files(sender, instance, **kwargs):
"""Deletes associated files before article deletion."""
if instance.cover_image:
instance.cover_image.delete(save=False) # Deletes the physical fileSignals eignen sich fuer leichtgewichtige Seiteneffekte (Logging, Cache-Invalidierung). Fuer aufwaendige Aufgaben wird Celery bevorzugt.
Frage 13: Wie integriert man Celery mit Django fuer asynchrone Aufgaben?
Celery ermoeglicht die Ausfuehrung von Hintergrundaufgaben, was fuer langlebige Operationen wie E-Mail-Versand oder Dateiverarbeitung unerlaesslich ist.
# celery_config.py
# Celery configuration in the Django project
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
app = Celery("myproject")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks() # Discovers tasks.py in each app
# tasks.py
from celery import shared_task
from django.core.mail import send_mass_mail
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_newsletter(self, article_id):
"""Sends newsletter asynchronously."""
try:
article = Article.objects.get(id=article_id)
subscribers = User.objects.filter(newsletter=True)
messages = [
(f"New: {article.title}", article.content[:200],
"noreply@example.com", [sub.email])
for sub in subscribers
]
send_mass_mail(messages, fail_silently=False)
except Article.DoesNotExist:
pass # Article was deleted in the meantime
except Exception as exc:
self.retry(exc=exc) # Automatic retry on error
# Calling from a view
# send_newsletter.delay(article.id) # Async execution
# send_newsletter.apply_async(args=[article.id], countdown=300) # 5-min delayCelery ist in der Produktion fuer jede Operation unerlaesslich, die die HTTP-Antwort nicht blockieren sollte.
Sicherheit und Authentifizierung
Frage 14: Wie schuetzt Django vor CSRF-Angriffen?
Django enthaelt einen integrierten CSRF-Schutz ueber eine Middleware, die bei jeder POST-Anfrage ein eindeutiges Token verifiziert.
# CSRF protection in forms
# The {% csrf_token %} template tag generates a hidden field
# For APIs (DRF), CSRF is often disabled in favor of tokens
# settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication", # Includes CSRF
"rest_framework.authentication.TokenAuthentication", # No CSRF
],
}
# For AJAX views with session auth
# The csrftoken cookie must be sent in the X-CSRFToken header# csrf_exemption.py
# Exempting a specific view (use with caution)
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
@ensure_csrf_cookie
def get_csrf_token(request):
"""Endpoint that forces sending the CSRF cookie to the client."""
return JsonResponse({"detail": "CSRF cookie set"})
@csrf_exempt # ⚠️ Use only for external webhooks
def stripe_webhook(request):
"""Stripe webhook - authenticated by signature, not CSRF."""
payload = request.body
sig_header = request.headers.get("Stripe-Signature")
# Verified by Stripe signature insteadCSRF sollte niemals global deaktiviert werden. csrf_exempt darf nur bei Endpunkten verwendet werden, die durch andere Mittel authentifiziert werden (Webhooks, API-Tokens).
Frage 15: Wie implementiert man benutzerdefinierte Authentifizierung in Django?
Django erlaubt das Ersetzen des Standard-User-Modells und die Anpassung des Authentifizierungs-Backends.
# models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class CustomUserManager(BaseUserManager):
"""Manager for the custom User model."""
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("Email is required")
email = self.normalize_email(email) # Normalizes the domain
user = self.model(email=email, **extra_fields)
user.set_password(password) # Hashes the password
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True) # Login by email
username = models.CharField(max_length=30, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
objects = CustomUserManager()
USERNAME_FIELD = "email" # Field used for login
REQUIRED_FIELDS = [] # Fields required in addition to USERNAME_FIELD
# settings.py
AUTH_USER_MODEL = "users.CustomUser" # Before the first migration!AUTH_USER_MODEL muss ganz am Anfang des Projekts definiert werden. Eine Aenderung nach den ersten Migrationen ist komplex und riskant.
Optimierung und Performance
Frage 16: Wie optimiert man Django-ORM-Abfragen?
Abfrageoptimierung ist entscheidend fuer die Performance. Mehrere Techniken reduzieren die Anzahl und die Kosten von SQL-Abfragen.
# query_optimization.py
from django.db.models import F, Q, Count, Avg, Prefetch
# 1. Only/Defer: load only needed fields
articles = Article.objects.only("title", "published_at") # SELECT title, published_at
heavy_articles = Article.objects.defer("content") # Everything EXCEPT content
# 2. SQL-level aggregations (not Python)
stats = Article.objects.aggregate(
total=Count("id"),
avg_views=Avg("view_count"),
)
# 3. F() expressions: SQL-level operations
Article.objects.filter(published=True).update(
view_count=F("view_count") + 1 # Atomic SQL increment
)
# 4. Q() objects: complex queries
results = Article.objects.filter(
Q(title__icontains="django") | Q(tags__name="python"),
~Q(status="draft"), # NOT draft
published_at__year=2026
)
# 5. Bulk operations: reduce INSERT/UPDATE queries
articles = [Article(title=f"Article {i}") for i in range(100)]
Article.objects.bulk_create(articles, batch_size=50) # 2 queries instead of 100
Article.objects.filter(status="draft").update(status="archived") # 1 querydjango-debug-toolbar sollte in der Entwicklung verwendet werden, um langsame Abfragen und N+1-Probleme zu identifizieren.
Frage 17: Wie implementiert man Caching in Django?
Django bietet ein mehrstufiges Caching-Framework: pro View, pro Template-Fragment oder fuer beliebige Daten.
# settings.py
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
}
}
# cache_strategies.py
from django.core.cache import cache
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
# Per-view cache: caches the entire HTTP response
@cache_page(60 * 15) # 15 minutes
def article_list(request):
return render(request, "articles/list.html", {"articles": Article.published.all()})
# Data cache: granular control
def get_popular_articles():
cache_key = "popular_articles_v1"
articles = cache.get(cache_key)
if articles is None:
articles = list(
Article.published.popular()[:10].values("id", "title", "view_count")
)
cache.set(cache_key, articles, timeout=60 * 30) # 30 min
return articles
# Cache invalidation
def invalidate_article_cache(article_id):
cache.delete(f"article_{article_id}")
cache.delete("popular_articles_v1")
cache.delete_pattern("article_list_*") # With django-redisRedis wird als Produktions-Cache-Backend empfohlen, da es Persistenz und erweiterte Funktionen bietet (Patterns, TTL).
Bereit für deine Django-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Migrationen und Datenbankverwaltung
Frage 18: Wie handhabt man komplexe Migrationen in Django?
Django-Migrationen verwalten die Datenbankschema-Evolution in versionierter und reproduzierbarer Weise.
# 0005_migrate_data.py
# Custom data migration
from django.db import migrations
def migrate_user_roles(apps, schema_editor):
"""Converts is_admin booleans to text roles."""
User = apps.get_model("users", "CustomUser")
# Use apps.get_model() to access the historical model
User.objects.filter(is_admin=True).update(role="admin")
User.objects.filter(is_admin=False, is_staff=True).update(role="manager")
User.objects.filter(is_admin=False, is_staff=False).update(role="user")
def reverse_migrate(apps, schema_editor):
"""Reverse migration for rollback."""
User = apps.get_model("users", "CustomUser")
User.objects.filter(role="admin").update(is_admin=True)
class Migration(migrations.Migration):
dependencies = [
("users", "0004_add_role_field"),
]
operations = [
migrations.RunPython(migrate_user_roles, reverse_migrate),
]Eine reverse-Funktion sollte immer bereitgestellt werden, um Rollbacks zu ermoeglichen. Migrationen muessen vor dem Deployment an einer Kopie der Produktionsdatenbank getestet werden.
Frage 19: Wie erstellt man benutzerdefinierte Indexe zur Optimierung?
Indexe beschleunigen haeufige Abfragen, erhoehen aber die Schreibkosten. Eine sorgfaeltige Auswahl ist unerlaesslich.
# models.py
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
status = models.CharField(max_length=20, db_index=True) # Simple index
published_at = models.DateTimeField(null=True)
author = models.ForeignKey("auth.User", on_delete=models.CASCADE)
class Meta:
indexes = [
# Composite index for frequent queries
models.Index(fields=["status", "-published_at"], name="idx_status_date"),
# Partial index: only published articles
models.Index(
fields=["published_at"],
condition=models.Q(status="published"),
name="idx_published_articles"
),
# GIN index for full-text search (PostgreSQL)
GinIndex(fields=["search_vector"], name="idx_search"),
]Zusammengesetzte Indexe folgen der Spaltenreihenfolge: Das selektivste Feld sollte zuerst stehen.
Testen und Qualitaet
Frage 20: Wie strukturiert man Tests in einem Django-Projekt?
Django bietet ein robustes Test-Framework basierend auf unittest, erweitert durch pytest-django fuer mehr Flexibilitaet.
# tests/test_views.py
from django.test import TestCase, Client
from django.urls import reverse
from rest_framework.test import APITestCase, APIClient
class ArticleViewTests(TestCase):
"""View tests with Django's test client."""
def setUp(self):
self.client = Client()
self.user = CustomUser.objects.create_user(
email="test@example.com", password="testpass123"
)
self.article = Article.objects.create(
title="Test Article",
content="Content here",
author=self.user,
status="published"
)
def test_article_list_returns_200(self):
response = self.client.get(reverse("article-list"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Article")
def test_create_article_requires_auth(self):
response = self.client.post(reverse("article-create"), {"title": "New"})
self.assertEqual(response.status_code, 302) # Redirects to login
class ArticleAPITests(APITestCase):
"""REST API tests with DRF."""
def setUp(self):
self.user = CustomUser.objects.create_user(
email="api@example.com", password="testpass123"
)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def test_create_article_via_api(self):
data = {"title": "API Article", "content": "Created via API"}
response = self.client.post("/api/articles/", data, format="json")
self.assertEqual(response.status_code, 201)
self.assertEqual(Article.objects.count(), 1)Tests sollten nach Domaene in Dateien getrennt werden: test_models.py, test_views.py, test_serializers.py, test_services.py.
Frage 21: Wie verwendet man Fixtures und Factories fuer Tests?
Factories (mit factory_boy) werden gegenueber JSON-Fixtures bevorzugt, da sie flexibler und wartbarer bei Testdaten sind.
# factories.py
import factory
from factory.django import DjangoModelFactory
class UserFactory(DjangoModelFactory):
class Meta:
model = CustomUser
email = factory.Sequence(lambda n: f"user{n}@example.com")
username = factory.Faker("user_name")
is_active = True
class ArticleFactory(DjangoModelFactory):
class Meta:
model = Article
title = factory.Faker("sentence", nb_words=5)
content = factory.Faker("paragraphs", nb=3)
author = factory.SubFactory(UserFactory) # Creates a user automatically
status = "published"
class Params:
draft = factory.Trait(status="draft", published_at=None)
# tests.py
def test_published_articles_count(self):
ArticleFactory.create_batch(5) # 5 published articles
ArticleFactory.create_batch(3, draft=True) # 3 drafts
self.assertEqual(Article.published.count(), 5)Factories sorgen fuer konsistente Testdaten und vermeiden Abhaengigkeiten zwischen Tests.
Fortgeschrittene Muster
Frage 22: Wie implementiert man WebSockets mit Django Channels?
Django Channels erweitert Django ueber HTTP hinaus und unterstuetzt WebSockets, Echtzeitprotokolle und Hintergrundaufgaben.
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
"""WebSocket consumer for real-time chat."""
async def connect(self):
self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
self.room_group = f"chat_{self.room_name}"
# Join the room group
await self.channel_layer.group_add(self.room_group, self.channel_name)
await self.accept()
async def disconnect(self, close_code):
# Leave the group
await self.channel_layer.group_discard(self.room_group, self.channel_name)
async def receive(self, text_data):
data = json.loads(text_data)
# Broadcast message to the entire group
await self.channel_layer.group_send(
self.room_group,
{"type": "chat.message", "message": data["message"],
"username": self.scope["user"].username}
)
async def chat_message(self, event):
# Send message to the WebSocket client
await self.send(text_data=json.dumps({
"message": event["message"],
"username": event["username"],
}))Django Channels verwendet ASGI (statt WSGI) und erfordert einen kompatiblen Server wie Daphne oder Uvicorn.
Frage 23: Erklaeren Sie das Repository- und Service-Layer-Pattern in Django
Das Service-Layer-Pattern trennt die Geschaeftslogik von Views und dem ORM, was Testing und Wartung erleichtert.
# services/article_service.py
from django.db import transaction
class ArticleService:
"""Service encapsulating article business logic."""
@staticmethod
def publish_article(article_id: int, user) -> Article:
"""Publishes an article with all validations."""
article = Article.objects.select_for_update().get(id=article_id)
if article.author != user:
raise PermissionError("Only the author can publish this article")
if article.status == "published":
raise ValueError("Article is already published")
article.status = "published"
article.published_at = timezone.now()
article.save(update_fields=["status", "published_at"])
# Side effects: notification, cache, analytics
send_newsletter.delay(article.id)
cache.delete("popular_articles_v1")
return article
@staticmethod
@transaction.atomic
def bulk_archive(article_ids: list[int], user) -> int:
"""Archives multiple articles in a transaction."""
updated = Article.objects.filter(
id__in=article_ids,
author=user,
status="published"
).update(status="archived", archived_at=timezone.now())
return updatedDas Service Layer ist der Einstiegspunkt fuer die gesamte Geschaeftslogik. Views und Serializer delegieren an den Service, niemals direkt an das ORM.
Frage 24: Wie verwaltet man Umgebungsvariablen und Multi-Environment-Konfiguration?
Die Konfigurationsverwaltung folgt den 12-Factor-App-Prinzipien: strikte Trennung zwischen Konfiguration und Code.
# settings/base.py
# Shared configuration across all environments
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv() # Loads the .env file
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] # Required, no default value
DEBUG = os.environ.get("DEBUG", "False").lower() == "true"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ.get("DB_NAME", "myapp"),
"USER": os.environ.get("DB_USER", "postgres"),
"HOST": os.environ.get("DB_HOST", "localhost"),
"PORT": os.environ.get("DB_PORT", "5432"),
}
}
# settings/production.py
from .base import *
DEBUG = False
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000 # 1 yearGeheimnisse sollten niemals im Code committet werden. Umgebungsvariablen oder ein Secrets Manager (Vault, AWS Secrets Manager) sind zu verwenden.
Frage 25: Wie deployt man eine Django-Anwendung in Produktion?
Produktions-Deployment erfordert eine umfassende Checkliste, die Sicherheit, Performance und Zuverlaessigkeit abdeckt.
# Django deployment checklist
# 1. Built-in verification command
# python manage.py check --deploy
# 2. WSGI/ASGI configuration for production
# gunicorn.conf.py
import multiprocessing
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1 # Recommended formula
worker_class = "gthread" # Threaded workers
threads = 4
max_requests = 1000 # Recycle workers to avoid memory leaks
max_requests_jitter = 50
timeout = 30
accesslog = "-" # Logs to stdout
errorlog = "-"# docker-compose.yml (typical configuration)
# Services: web (gunicorn), db (postgres), redis (cache/celery), worker (celery)
# 3. Static files
# python manage.py collectstatic --noinput
# Serve via nginx or CDN (WhiteNoise for simple cases)
# 4. Nginx configuration
# - Proxy to gunicorn on port 8000
# - Serve /static/ and /media/ directly
# - Enable gzip, HTTP/2, and security headerspython manage.py check --deploy sollte vor jedem Produktions-Release ausgefuehrt werden. Dieser Befehl ueberprueft wesentliche Sicherheitseinstellungen.
Fazit
Diese 25 Fragen decken die wesentlichen Aspekte von Django- und Python-Vorstellungsgespraechen ab, von den Grundlagen der MVT-Architektur bis hin zu Produktions-Deployment-Patterns.
Vorbereitungs-Checkliste:
- ✅ MVT-Architektur und Request Lifecycle
- ✅ ORM: QuerySets, N+1, select_related, prefetch_related
- ✅ Django REST Framework: Serializer, Paginierung, Berechtigungen
- ✅ Sicherheit: CSRF, Authentifizierung, Berechtigungen
- ✅ Performance: ORM-Optimierung, Caching, Indexe
- ✅ Testing: TestCase, APITestCase, Factories
- ✅ Fortgeschrittene Muster: Channels, Service Layer, Deployment
Jede Frage verdient eine tiefere Erkundung mit der offiziellen Django-Dokumentation. Interviewer schaetzen Kandidaten, die die Feinheiten des Frameworks verstehen und ihre technischen Entscheidungen begruenden koennen.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
Verwandte Artikel

Django 5: Eine REST-API mit Django REST Framework erstellen
Vollständige Anleitung zum Erstellen einer professionellen REST-API mit Django 5 und DRF. Serializer, ViewSets, JWT-Authentifizierung und Best Practices erklärt.

Django Interview-Fragen: ORM, Middleware und DRF im Detail
Django Interview-Fragen für 2026: ORM-Optimierung, Middleware-Architektur und Django REST Framework. Mit Codebeispielen für Django 5.2 LTS.

Top 25 Data-Analytics-Interviewfragen 2026 – Mit SQL, Python und Praxisbeispielen
Die 25 häufigsten Interviewfragen für Data-Analyst-Positionen in 2026. Mit SQL-Abfragen, Python-Code, Statistikgrundlagen und Verhaltenstipps.