THE MODN CHRONICLES

Interview Prep

Interview Questions for Django — MVT, ORM, REST Framework, and What Python Backend Interviews Actually Test

Django is the most tested Python web framework in backend and full-stack interviews. The questions cover MVT architecture, ORM queries, middleware, and REST framework. Interviewers want code, not definitions.

Developer writing Python Django code during interview preparation

Django powers Instagram, Pinterest, Spotify, and thousands of startups — every Python backend interview includes Django questions.

Django Is the Python Interview Framework

Django is the most tested Python web framework. Every Python backend interview includes Django questions — MVT architecture, ORM queries, middleware, and REST framework. Instagram, Pinterest, and Spotify all run on Django. For Python backend or full-stack roles, Django is non-negotiable.

The interview pattern is consistent: architecture first (MVT, request lifecycle), ORM second (relationships, QuerySets, N+1 problems), then REST Framework for API building. Senior candidates get middleware, security, and deployment questions. This guide covers the actual questions with code examples and the depth interviewers expect.

If you cannot explain the difference between MVT and MVC, or write a QuerySet with select_related from memory, you are not ready for a Django interview. Interviewers want working code, not textbook answers.

Core Concepts

These three questions appear in every Django interview. They test whether you understand how Django works architecturally.

Q1: What is MVT architecture and how does it differ from MVC?

Why they ask: This is the opening question in most Django interviews. Interviewers want the MVT-to-MVC mapping and the key difference — Django's framework itself acts as the controller.

# MVT vs MVC:
# Model (MVT) → Model (MVC)      — Data layer
# View (MVT)  → Controller (MVC) — Business logic
# Template    → View (MVC)       — Presentation

# Django's framework itself acts as the controller.
# urls.py routes requests to the correct view.

# Request Lifecycle:
# 1. HTTP request → URL resolver matches pattern
# 2. View processes request (queries Model)
# 3. View passes context to Template
# 4. Template renders → Django returns HttpResponse

Q2: What is the difference between a project and an app?

Why they ask: This tests whether you understand Django's modular architecture. Candidates who have only built tutorial projects often confuse the two.

# Project = entire web application (config container)
# App = modular component (reusable across projects)

# myproject/
#   manage.py
#   myproject/settings.py, urls.py, wsgi.py
#   users/       ← app
#   blog/        ← app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'users',
    'blog',
]
# If a feature could be standalone, make it an app.

Q3: Explain Django's request-response cycle

Why they ask: Interviewers want the complete chain — URL resolver, middleware, view, template, response.

# 1. Browser sends HTTP request
# 2. WSGI/ASGI creates HttpRequest object
# 3. Middleware processes request (top → bottom)
# 4. URL resolver matches pattern:

from django.urls import path, include
urlpatterns = [
    path('api/users/', include('users.urls')),
    path('api/blog/', include('blog.urls')),
]

# 5. View called → queries ORM → renders Template/JSON
# 6. Middleware processes response (bottom → top)
# 7. Django returns HttpResponse
# Key: middleware runs TWICE. Order matters.

ORM & Models

Django's ORM is one of its strongest features — and the most tested area. These four questions test whether you can write efficient database queries without common performance traps.

Q1: How do you create a model with relationships?

Why they ask: Database modeling is fundamental. Interviewers want ForeignKey, ManyToManyField, and OneToOneField — and when to use each.

from django.db import models
from django.contrib.auth.models import User

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE,
                               related_name='articles')
    created_at = models.DateTimeField(auto_now_add=True)

class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)
    articles = models.ManyToManyField(Article, related_name='tags')

# on_delete: CASCADE (delete), PROTECT (prevent), SET_NULL, DO_NOTHING

Q2: Explain QuerySet lazy evaluation

Why they ask: Candidates who do not understand lazy evaluation write inefficient code with unnecessary database calls.

# QuerySets are LAZY — no DB hit until evaluated
qs = Article.objects.filter(author=user)   # no DB hit
qs = qs.exclude(status='draft')            # no DB hit
qs = qs.order_by('-created_at')            # no DB hit

# Triggers: iteration, slicing, list(), len(), bool()

# BAD:  len(articles) fetches ALL rows to count
# GOOD: articles.exists() → SELECT 1 LIMIT 1
# BAD:  len(articles) then iterate → 2 DB hits
# GOOD: articles.exists() then iterate → efficient

# Cache: after first eval, QuerySet caches results
qs = Article.objects.all()
list(qs)  # DB hit, cached
list(qs)  # no DB hit

Q3: What is the N+1 query problem and how do you fix it?

Why they ask: The most common Django performance issue. Interviewers want select_related and prefetch_related with the difference between them.

# BAD — N+1 queries (1 + 100 = 101 DB hits)
articles = Article.objects.all()
for article in articles:
    print(article.author.username)  # each = 1 query

# FIX: select_related (FK/OneToOne — SQL JOIN)
articles = Article.objects.select_related('author').all()
# 1 query with JOIN — no extra queries

# FIX: prefetch_related (M2M/reverse FK — 2 queries)
articles = Article.objects.prefetch_related('tags').all()
# Query 1: articles, Query 2: tags WHERE id IN (...)

# Chain: .select_related('author').prefetch_related('tags')

Q4: How do you write custom model managers?

Why they ask: Custom managers show ORM depth. Interviewers want to see reusable query patterns encapsulated in the model layer.

class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(status='published')
    def by_author(self, user):
        return self.get_queryset().filter(author=user)
    def recent(self, limit=10):
        return self.get_queryset().order_by('-created_at')[:limit]

class Article(models.Model):
    title = models.CharField(max_length=200)
    status = models.CharField(max_length=10)
    objects = models.Manager()        # default
    published = PublishedManager()    # custom

# Article.published.all()           → only published
# Article.published.by_author(user) → published by user
# Article.published.recent(5)       → 5 most recent
Python code on screen showing Django ORM queries and model definitions

Django's ORM turns Python classes into database tables — mastering QuerySets and relationships is what interviewers test most.

Views & URLs

Q1: Function-based vs class-based views — when do you use each?

Why they ask: Candidates who only use one approach signal limited experience. Interviewers want both implementations for the same feature.

# FBV — simple, explicit
from django.http import JsonResponse

def article_list(request):
    if request.method == 'GET':
        data = [{'id': a.id, 'title': a.title}
                for a in Article.published.recent(20)]
        return JsonResponse({'articles': data})
    elif request.method == 'POST':
        article = Article.objects.create(
            title=request.POST.get('title'), author=request.user)
        return JsonResponse({'id': article.id}, status=201)

# CBV — reusable, DRY, built-in mixins
from django.views import View
class ArticleListView(View):
    def get(self, request):
        data = [{'id': a.id, 'title': a.title}
                for a in Article.published.recent(20)]
        return JsonResponse({'articles': data})

# FBV: simple logic, one-off views, maximum readability
# CBV: CRUD ops, mixins (LoginRequiredMixin), shared patterns

Q2: How does URL routing work?

Why they ask: Interviewers want path(), include(), named URLs, and URL parameters — the complete routing picture.

# Root urls.py
from django.urls import path, include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/articles/', include('articles.urls')),
]

# App urls.py (articles/urls.py)
app_name = 'articles'
urlpatterns = [
    path('', views.article_list, name='list'),
    path('<int:pk>/', views.article_detail, name='detail'),
    path('<slug:slug>/', views.article_by_slug, name='by-slug'),
]

# URL params → keyword args:
def article_detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    return JsonResponse({'title': article.title})

# reverse(): reverse('articles:detail', kwargs={'pk': 42})
# CBVs: path('', ArticleListView.as_view(), name='list')

Q3: What are generic views and when do you use them?

Why they ask: Generic views eliminate boilerplate. Interviewers want ListView, DetailView, CreateView — and proof you can customize them.

from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin

class ArticleListView(ListView):
    model = Article
    template_name = 'articles/list.html'
    paginate_by = 20
    def get_queryset(self):
        return Article.published.select_related('author')

class ArticleDetailView(DetailView):
    model = Article
    def get_queryset(self):
        return Article.published.prefetch_related('tags')

class ArticleCreateView(LoginRequiredMixin, CreateView):
    model = Article
    fields = ['title', 'content', 'status']
    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

# Handles GET/POST routing, validation, pagination, 404s.
# Use for standard CRUD. Use FBVs for complex logic.

Practice Django Interview Questions Live

Reading questions is not the same as answering them under pressure. Practice with timed mock interviews that test MVT architecture, ORM queries, and REST API design.

TRY INTERVIEW PRACTICE →

Middleware & Security

Q1: What is middleware and how does it work?

Why they ask: Middleware is Django's request/response pipeline. Interviewers want execution order and custom middleware code.

# Order matters: top→bottom on request, bottom→top on response.
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'myapp.middleware.RequestLoggingMiddleware',
]

# Custom middleware:
import time, logging
logger = logging.getLogger(__name__)

class RequestLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        start = time.time()
        response = self.get_response(request)
        logger.info(f"{request.method} {request.path} — {time.time()-start:.2f}s")
        return response
    def process_exception(self, request, exception):
        logger.error(f"Exception: {request.path}: {exception}")
        return None

Q2: How does Django prevent CSRF attacks?

Why they ask: CSRF protection is a security fundamental. Interviewers want the token mechanism and AJAX handling.

# 1. CsrfViewMiddleware generates unique token per session
# 2. Token embedded in forms: {% csrf_token %}
# 3. On POST/PUT/DELETE, Django verifies token
# 4. Missing/wrong token → 403 Forbidden

# AJAX: send via X-CSRFToken header
# fetch('/api/', { headers: {'X-CSRFToken': getCookie('csrftoken')} })

# Exempt views (external webhooks):
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def webhook_handler(request):
    pass  # external services lack CSRF tokens

# DRF: TokenAuth/JWT skip CSRF, SessionAuth enforces it.

Q3: How does Django handle authentication?

Why they ask: Interviewers want the built-in User model, login/logout flow, and custom User models.

from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required

def login_view(request):
    user = authenticate(request,
        username=request.POST['username'],
        password=request.POST['password'])
    if user is not None:
        login(request, user)  # creates session
        return redirect('dashboard')
    return render(request, 'login.html', {'error': 'Invalid credentials'})

@login_required(login_url='/login/')
def dashboard(request):
    return render(request, 'dashboard.html')

# Custom User model (set BEFORE first migration):
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
    phone = models.CharField(max_length=15, blank=True)
# AUTH_USER_MODEL = 'users.CustomUser'

REST Framework

Q1: What are serializers and how do they work?

Why they ask: Serializers bridge Django models and JSON. Interviewers want ModelSerializer, validation, and nested serializers.

from rest_framework import serializers

class ArticleSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True, read_only=True)  # nested
    author_name = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'author',
                  'author_name', 'tags', 'created_at']
        read_only_fields = ['author', 'created_at']

    def get_author_name(self, obj):
        return obj.author.get_full_name() or obj.author.username

    def validate_title(self, value):
        if len(value) < 5:
            raise serializers.ValidationError("Title too short.")
        return value

    def create(self, validated_data):
        validated_data['author'] = self.context['request'].user
        return super().create(validated_data)

# Serializers handle: Model→JSON (responses), JSON→validated
# data (create/update), field + object-level validation

Q2: ViewSets vs APIView — when do you use each?

Why they ask: APIView gives full control, ViewSets give convention-based CRUD with router registration.

from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework.routers import DefaultRouter

# APIView — explicit HTTP method handling
class ArticleListAPIView(APIView):
    def get(self, request):
        articles = Article.published.all()
        return Response(ArticleSerializer(articles, many=True).data)
    def post(self, request):
        serializer = ArticleSerializer(data=request.data,
                                       context={'request': request})
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=201)

# ViewSet — auto-generates URLs via router
class ArticleViewSet(ModelViewSet):
    queryset = Article.objects.select_related('author')
    serializer_class = ArticleSerializer
    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

router = DefaultRouter()
router.register(r'articles', ArticleViewSet)
# Generates: /articles/, /articles/{pk}/

# APIView: custom endpoints, webhooks, non-CRUD
# ViewSet: standard CRUD with auto-routing

Q3: How do you implement authentication in DRF?

Why they ask: API authentication differs from session-based auth. Interviewers want TokenAuth, JWT, and SessionAuth.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

# Token Auth: Authorization: Token 9944b09199c62bcf...
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=user)

# JWT (simplejwt): Authorization: Bearer eyJ0eXAi...
from rest_framework_simplejwt.views import (
    TokenObtainPairView, TokenRefreshView)
urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view()),
    path('api/token/refresh/', TokenRefreshView.as_view()),
]

# Per-view override:
class PublicArticleList(APIView):
    authentication_classes = []
    permission_classes = [AllowAny]

# Token: stateful (DB), mobile apps
# JWT: stateless, microservices
# Session: browser cookies, web apps

How to Prepare — By Role

The depth of Django knowledge tested varies by experience level:

Junior Developer (1 week)

MVT architecture, basic ORM, function-based views. Build a CRUD app — models, URL routing, views, templates. Know filter, exclude, order_by.

Mid-Level Developer (2 weeks)

Add DRF, middleware, caching, Celery. Know serializers, ViewSets, API auth, N+1 problem, select_related/prefetch_related, custom middleware, Redis.

Senior Developer (1 week review)

System design, deployment (Gunicorn/Nginx), database indexing, django-debug-toolbar, horizontal scaling, signals, Django vs FastAPI vs Flask trade-offs.

Practice With Real Interview Simulations

Practice with timed mock interviews that test MVT architecture, ORM queries, and API design decisions with confidence.

TRY INTERVIEW PRACTICE →

Django interviews follow a clear pattern: architecture first, ORM second, REST framework third. The developer who writes QuerySets with select_related from memory gets the offer.

Django is the backbone of Python backend development. Master the ORM, build REST APIs fluently, understand middleware deeply, and you will handle any Django interview.

Prepare for Your Django Interview

Practice with AI-powered mock interviews and get your resume ATS-ready.