Top 60 Django Interview Questions (2026)

The 60 Django questions interviewers actually ask, with direct answers, runnable code, and what the interviewer is listening for. Grouped for freshers, intermediate, and experienced rounds.

60 questions with answers

What Is Django?

Key Takeaways

  • Django is a high-level Python web framework that follows the Model-View-Template pattern and ships batteries included: ORM, admin, auth, forms, and security.
  • It's built for fast, secure development, so interviews probe how well you use the ORM, the request/response cycle, and the built-in protections rather than raw syntax.
  • Questions climb from MVT and models at the fresher level to querysets, middleware, and signals at intermediate, then scaling, caching, and security at senior.
  • This page is a question bank: work your tier first, read one tier up, and say answers out loud because delivery is evaluated too.

Django is a high-level Python web framework created at the Lawrence Journal-World newspaper and released publicly in 2005. It follows the Model-View-Template (MVT) pattern and describes itself as batteries included: an object-relational mapper, an automatic admin interface, an authentication system, form handling, and a set of security defaults all ship in the box. The official Django documentation calls it a framework that lets developers build web applications quickly while encouraging clean, pragmatic design. In interviews, Django questions test whether you understand the request/response cycle, how the ORM turns Python into SQL, and when to reach for the framework's built-ins versus rolling your own. This page collects the 60 questions that come up most, each with a direct answer and runnable code. Increasingly the first backend round is a live AI coding interview, so pair this bank with our AI interview preparation guides for the format side.

60Questions with answers on this page
3Difficulty tiers: freshers, intermediate, experienced
24Runnable code snippets you can practice from
45-60 minTypical length of a Django technical round

Watch: Python Django Web Framework - Full Course for Beginners

Video: Python Django Web Framework - Full Course for Beginners (freeCodeCamp.org, YouTube)

Test yourself and earn a certificate

10 quick questions. Score 70%+ to download your Django certificate.

Jump to quiz

All Questions on This Page

60 questions
Django Interview Questions for Freshers
  1. 1. What is Django and what problems does it solve?
  2. 2. What is the MVT architecture in Django?
  3. 3. What is the difference between a Django project and an app?
  4. 4. What is the Django ORM and why use it?
  5. 5. How do you define a model in Django?
  6. 6. What are migrations and which commands manage them?
  7. 7. What is a view in Django, and what is the difference between function-based and class-based views?
  8. 8. How does URL routing work in Django?
  9. 9. What is the Django template language and what can it do?
  10. 10. What is the Django admin and why is it useful?
  11. 11. What lives in the settings.py file?
  12. 12. What is the difference between get(), filter(), and all() on a manager?
  13. 13. What is the difference between static files and media files?
  14. 14. What does it mean that querysets are lazy?
  15. 15. What is CSRF and how does Django protect against it?
  16. 16. How do Django forms work?
  17. 17. What is the difference between null=True and blank=True?
  18. 18. What are WSGI and ASGI in Django?
  19. 19. What is the Django shell and when do you use it?
  20. 20. What are the three relationship fields in Django and when do you use each?
  21. 21. What do render() and redirect() do in a view?
Django Intermediate Interview Questions
  1. 22. What is the difference between select_related and prefetch_related?
  2. 23. What is the N+1 query problem and how do you fix it in Django?
  3. 24. How does middleware work and when would you write your own?
  4. 25. What are Django signals and when should you use them?
  5. 26. How do annotate() and aggregate() differ?
  6. 27. What are Q objects and F expressions used for?
  7. 28. How do you manage database transactions in Django?
  8. 29. How do authentication and authorization work in Django?
  9. 30. How do sessions work in Django?
  10. 31. What is a custom model manager and why write one?
  11. 32. How does caching work in Django?
  12. 33. What is Django REST Framework and what does a serializer do?
  13. 34. What are viewsets and routers in DRF?
  14. 35. What is a context processor?
  15. 36. What does the Meta class in a model configure?
  16. 37. What do get_object_or_404 and get_list_or_404 do?
  17. 38. What does the related_name argument on a ForeignKey do?
  18. 39. What are the on_delete options on a ForeignKey?
  19. 40. How do you test a Django application?
  20. 41. How do bulk_create and update() work, and what do they skip?
Django Interview Questions for Experienced Developers
  1. 42. Walk through the full request/response cycle in Django.
  2. 43. How do you scale a Django application?
  3. 44. How do you handle background and asynchronous tasks?
  4. 45. How do you implement a custom user model, and what breaks if you add it late?
  5. 46. When would you drop from the ORM to raw SQL?
  6. 47. What security protections does Django provide, and what must you still do?
  7. 48. How do you diagnose and fix a slow Django page?
  8. 49. When would you use a signal versus overriding save()?
  9. 50. How do you prevent race conditions on concurrent database writes?
  10. 51. How do you structure settings and secrets across environments?
  11. 52. How do database routers and multiple databases work in Django?
  12. 53. What is the contenttypes framework and when do you use generic relations?
  13. 54. What is the state of async support in Django?
  14. 55. How do you run migrations safely in production?
  15. 56. When do you use middleware versus a view decorator versus a mixin?
  16. 57. What does a production Django deployment stack look like?
  17. 58. What are common Django gotchas experienced developers watch for?
  18. 59. How do you handle authentication and permissions in a DRF API?
  19. 60. When would you choose session authentication over JWT for a Django API?

Django Interview Questions for Freshers

Freshers21 questions

The fundamentals every entry-level round checks. If any answer here surprises you, that's your study list.

Q1. What is Django and what problems does it solve?

Django is a high-level Python web framework that ships with an ORM, an admin site, authentication, forms, and security defaults built in. It handles the plumbing every web app needs so you write features instead of boilerplate.

It solves the repetitive parts of web development: mapping URLs to code, talking to a database without hand-writing SQL, rendering HTML, validating input, and blocking common attacks. That's why a small team can ship a real product fast.

Key point: A one-line definition plus two concrete built-ins (the ORM and the admin) beats a memorized feature list. Interviewers open with this to hear how you organize an answer.

Watch a deeper explanation

Video: Python Django Explained In 8 Minutes (Dennis Ivy, YouTube)

Q2. What is the MVT architecture in Django?

MVT is Model, View, Template. The Model defines your data and talks to the database, the View holds the request-handling logic and decides what data to return, and the Template renders that data into HTML.

It's Django's take on MVC. The framework itself plays the controller role by routing incoming URLs to the right view, so you write models, views, and templates and let Django wire them together.

PartResponsibilityLives in
ModelData structure and database accessmodels.py
ViewRequest logic, choose and return dataviews.py
TemplatePresent data as HTMLtemplates/

Key point: The common follow-up is 'how does MVT differ from MVC?'. Say Django is the controller and you're done.

Q3. What is the difference between a Django project and an app?

A project is the whole website: settings, the root URL config, and the collection of apps that make it up. An app is a self-contained module that does one thing, like a blog, a payments feature, or user accounts.

One project holds many apps, and a well-written app can be reused across projects. Keeping features in separate apps is how Django codebases stay organized as they grow.

Key point: Mention reusability. Interviewers like hearing that apps are meant to be pluggable, not just folders.

Q4. What is the Django ORM and why use it?

The ORM (object-relational mapper) lets you work with the database using Python classes and objects instead of writing SQL. A model class maps to a table, an instance maps to a row, and methods like filter() and get() build the queries for you.

You use it because it's faster to write, portable across databases (SQLite, PostgreSQL, MySQL), and safe by default: queries are parameterized, so ordinary use won't expose you to SQL injection.

python
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    published = models.DateField()

# query with Python, not SQL
recent = Book.objects.filter(published__year=2026).order_by("title")

Key point: Say the ORM is convenient but not free: you should still know what SQL it generates. That awareness is what separates juniors from mid-level.

Watch a deeper explanation

Video: Django Tutorial for Beginners | Full Course (Telusko, YouTube)

Q5. How do you define a model in Django?

You subclass django.db.models.Model and declare each column as a class attribute using a field type: CharField for short text, TextField for long text, IntegerField, DateTimeField, ForeignKey for relations, and so on. Django reads those fields to build the table.

Each field takes options like max_length, null, blank, default, and unique. Once the model is defined, makemigrations and migrate create the matching table.

python
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=120)
    email = models.EmailField(unique=True)
    joined = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

Q6. What are migrations and which commands manage them?

Migrations turn changes in your models into versioned, ordered database schema changes. They keep your Python models and the actual database structure in sync, and they're stored as files so the whole team applies the same changes.

makemigrations reads model changes and writes migration files; migrate applies pending migrations to the database. showmigrations lists what's applied, and sqlmigrate prints the SQL a migration will run.

bash
python manage.py makemigrations   # create migration files from model changes
python manage.py migrate           # apply them to the database
python manage.py showmigrations    # see what is applied

Key point: If asked what makemigrations does versus migrate, be precise: one writes the plan, the other executes it. Mixing them up is a common junior slip.

Q7. What is a view in Django, and what is the difference between function-based and class-based views?

A view is the code that takes a web request and returns a web response. Function-based views (FBVs) are plain functions that receive the request and return an HttpResponse. Class-based views (CBVs) are classes that map HTTP methods to methods like get() and post() and offer reusable generic views.

FBVs are explicit and easy to read for simple logic. CBVs shine when you want the built-in generic views (ListView, DetailView, CreateView) to remove repetitive create/read/update/delete code.

python
from django.http import HttpResponse
from django.views import View

# function-based view
def hello(request):
    return HttpResponse("Hello")

# class-based view
class HelloView(View):
    def get(self, request):
        return HttpResponse("Hello")

Key point: Have a rule ready: FBV for one-off custom logic, CBV when a generic view already does most of the work. the question needs your judgment, not a preference.

Q8. How does URL routing work in Django?

Django matches an incoming path against a list of URL patterns defined with path() or re_path() in a urls.py. The first pattern that matches wins, and Django calls the view attached to it, passing any captured parameters.

Projects usually keep a root urls.py that includes each app's urls.py with include(), so routing stays modular. Naming a pattern lets you reverse it with reverse() or the {% url %} template tag instead of hardcoding paths.

python
from django.urls import path
from . import views

urlpatterns = [
    path("books/", views.book_list, name="book-list"),
    path("books/<int:pk>/", views.book_detail, name="book-detail"),
]

Q9. What is the Django template language and what can it do?

The Django template language (DTL) renders HTML from context data using {{ variables }}, {% tags %} for logic like loops and conditionals, and filters like {{ name|upper }} to transform values. It's deliberately limited so presentation logic stays in templates and real logic stays in Python.

Templates support inheritance: a base template defines blocks, and child templates override them, which keeps shared layout in one place.

html
{% extends 'base.html' %}
{% block content %}
  <ul>
  {% for book in books %}
    <li>{{ book.title|title }}</li>
  {% endfor %}
  </ul>
{% endblock %}

Q10. What is the Django admin and why is it useful?

The Django admin is an auto-generated web interface for managing your data. Register a model and you get create, read, update, and delete screens for it, with search, filters, and permissions, without writing any of that UI yourself.

It's genuinely useful for internal tools, content management, and early-stage debugging. You customize it with ModelAdmin classes to control which fields show, how they're filtered, and who can access them.

python
from django.contrib import admin
from .models import Book

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ("title", "published")
    search_fields = ("title",)
    list_filter = ("published",)

Key point: Say the admin is for staff, not end users. Candidates who suggest exposing it as a public UI raise a flag.

Q11. What lives in the settings.py file?

settings.py holds a project's configuration in one place: the database connection, INSTALLED_APPS, the MIDDLEWARE chain, template directories, static and media settings, the SECRET_KEY, the DEBUG flag, ALLOWED_HOSTS, and the time zone. Django reads it at startup to wire everything together.

In production you split or override settings per environment and pull secrets from environment variables, never hardcoding them. DEBUG must be False in production, and the SECRET_KEY must stay out of version control.

Key point: If you say DEBUG stays True in production, that's an instant red flag. Know that DEBUG leaks stack traces and settings.

Q12. What is the difference between get(), filter(), and all() on a manager?

all() returns every row as a queryset. filter() returns a queryset of rows matching the conditions, which may be zero, one, or many. get() returns exactly one object and raises DoesNotExist if none match or MultipleObjectsReturned if more than one does.

Use get() when you expect a single, unique result (usually by primary key), and filter() when you expect a set. Wrapping get() in a try/except, or using get_object_or_404, is the safe pattern.

python
Book.objects.all()                      # queryset of every book
Book.objects.filter(author__name="Asha") # queryset, could be empty
Book.objects.get(pk=7)                   # one object or raises

Key point: The trap is calling get() where results might not be unique. The two exceptions it can raise matters.

Q13. What is the difference between static files and media files?

Static files are assets that ship with your code and don't change per user: CSS, JavaScript, images that are part of the design. Media files are user-uploaded content: profile pictures, document attachments, anything submitted at runtime.

Django serves them through different settings (STATIC_URL and STATICFILES for static, MEDIA_URL and MEDIA_ROOT for media). In production a web server or CDN serves static files, and media usually lives in object storage.

Q14. What does it mean that querysets are lazy?

Building a queryset runs no SQL. Django waits until you actually need the data, then evaluates the query. So you can chain filter().exclude().order_by() and only one query fires, when the result is consumed.

Evaluation happens when you iterate the queryset, call list() or len(), slice to a single index, or test it in a boolean context. Understanding this explains why chaining is cheap and why a stray len() can trigger an unwanted query.

python
qs = Book.objects.filter(published__year=2026)  # no SQL yet
qs = qs.order_by("title")                       # still no SQL
for book in qs:                                 # SQL runs here
    print(book.title)

Key point: This laziness sets up the N+1 and caching questions at the next tier. Nail the four triggers of evaluation.

Q15. What is CSRF and how does Django protect against it?

Cross-site request forgery tricks a logged-in user's browser into sending a state-changing request to your site from a malicious page. Django's CsrfViewMiddleware defends against it by requiring a secret token on POST, PUT, PATCH, and DELETE requests.

In templates you add {% csrf_token %} inside forms; Django checks the submitted token against the one tied to the session. Requests without a valid token are rejected with a 403.

html
<form method="post">
  {% csrf_token %}
  <input name="title">
  <button type="submit">Save</button>
</form>

Q16. How do Django forms work?

A Form class declares fields with their types and validation rules. Django renders those fields to HTML, and on submission it validates the data: form.is_valid() runs the checks and populates form.cleaned_data with typed, safe values.

ModelForm builds a form directly from a model, so you don't repeat field definitions and can call form.save() to write to the database. Forms centralize validation and protect against bad input.

python
from django import forms
from .models import Book

class BookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ["title", "published"]

# in a view
form = BookForm(request.POST)
if form.is_valid():
    form.save()

Q17. What is the difference between null=True and blank=True?

null=True controls the database: it allows the column to store NULL. blank=True controls validation: it allows forms and the admin to accept an empty value. They live at different layers.

For text-based fields (CharField, TextField) the convention is to use blank=True but not null=True, because Django stores an empty string rather than NULL for missing text, which avoids two ways to represent no value.

OptionLayerEffect
null=TrueDatabaseColumn can be NULL
blank=TrueValidationField can be left empty in forms

Key point: The text-field convention (blank but not null) is a favorite follow-up. Explaining the empty-string reasoning shows real experience.

Q18. What are WSGI and ASGI in Django?

WSGI and ASGI are the interfaces between a Django app and the server that runs it. WSGI is the older synchronous standard; ASGI is the newer one that also supports asynchronous views, WebSockets, and long-lived connections.

Django generates a wsgi.py and an asgi.py in every project. You run the app behind a server like Gunicorn (WSGI) or Uvicorn/Daphne (ASGI) in production; the built-in runserver is for development only.

Key point: If you only know WSGI, at least name ASGI as the async path. Saying runserver is production-ready is a mistake to avoid.

Q19. What is the Django shell and when do you use it?

The Django shell is an interactive Python session with your project's settings and models loaded. You start it with python manage.py shell, then import models and run queries, test ORM calls, or inspect data directly.

It's the fastest way to experiment with querysets, reproduce a bug, or check what SQL a query generates before you put it in code. shell_plus from django-extensions auto-imports your models to save typing.

bash
python manage.py shell
>>> from books.models import Book
>>> Book.objects.filter(published__year=2026).count()
12

Q20. What are the three relationship fields in Django and when do you use each?

ForeignKey models a many-to-one relation: many books belong to one author. ManyToManyField models a many-to-many relation: a book can have many tags and a tag many books, which Django backs with a join table. OneToOneField models a strict one-to-one link, often used to extend another model.

Pick the field that matches the real-world cardinality. A profile that extends a user is one-to-one; a book's author is many-to-one; a book's tags are many-to-many.

python
class Author(models.Model):
    name = models.CharField(max_length=120)

class Tag(models.Model):
    label = models.CharField(max_length=40)

class Book(models.Model):
    author = models.ForeignKey(Author, on_delete=models.CASCADE)  # many-to-one
    tags = models.ManyToManyField(Tag)                            # many-to-many

Key point: The follow-up is 'what table does ManyToMany create?'. Knowing it builds a hidden join table shows you understand what the ORM does underneath.

Q21. What do render() and redirect() do in a view?

render() combines a template with a context dictionary and returns an HttpResponse containing the rendered HTML in one step, so you don't build the response by hand. redirect() returns an HTTP redirect response that sends the browser to another URL, a view name, or a model's absolute URL.

The pattern to remember is redirect after a successful POST, so a page refresh doesn't resubmit the form. Use render() to show a page and redirect() to move the user after an action.

python
from django.shortcuts import render, redirect

def create_book(request):
    if request.method == "POST":
        form = BookForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("book-list")   # post-then-redirect
    return render(request, "new.html", {"form": BookForm()})
Back to question list

Django Intermediate Interview Questions

Intermediate20 questions

For candidates with working experience: ORM depth, middleware, signals, and the questions that separate users from understanders.

Q23. What is the N+1 query problem and how do you fix it in Django?

N+1 happens when you fetch a list of objects with one query, then trigger a separate query for each object's related data inside a loop. A page showing 100 books plus each author fires 1 query for the books and 100 for the authors: 101 queries where 1 or 2 would do.

The fix is to tell the ORM up front what you'll need: select_related for to-one relations, prefetch_related for to-many. Tools like Django Debug Toolbar or logging the queries reveal N+1 fast.

python
# N+1: one query for books, one per author
for book in Book.objects.all():
    print(book.author.name)

# fixed: one JOINed query
for book in Book.objects.select_related("author"):
    print(book.author.name)

Key point: If you can The tool you'd use to detect it (Debug Toolbar, query logging), you sound like someone who has actually shipped Django.

Q24. How does middleware work and when would you write your own?

Middleware is an ordered chain of components that wrap the view. On the way in, each middleware can inspect or modify the request; on the way out, each can inspect or modify the response. Django's own auth, session, CSRF, and security features are middleware.

You write custom middleware for cross-cutting concerns that apply to many views: request timing, adding headers, tenant resolution, or rate limiting. Order in the MIDDLEWARE list matters because it defines the wrapping sequence.

python
class TimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        import time
        start = time.perf_counter()
        response = self.get_response(request)
        response['X-Elapsed'] = f"{time.perf_counter() - start:.3f}"
        return response

Q25. What are Django signals and when should you use them?

Signals let one part of your code notify another when something happens, without the two being directly coupled. Built-in signals include pre_save, post_save, pre_delete, and post_delete on models, plus request-lifecycle signals.

Use them for genuinely decoupled side effects: creating a profile when a user is created, invalidating a cache when a record changes. The caution: signals hide control flow, so for logic tied to one place, an explicit call or a model save() override is clearer.

python
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

Key point: Volunteer the downside. Saying signals can obscure flow shows you'd reach for them deliberately, not reflexively.

Q26. How do annotate() and aggregate() differ?

aggregate() collapses a whole queryset into a single dictionary of computed values: total count, average price, max date. annotate() adds a computed value to each row of the queryset, so each object carries its own aggregate.

Use aggregate() for one summary number over the set, and annotate() when you need a per-object figure, like each author with their book count. annotate() commonly pairs with values() and group-by behavior.

python
from django.db.models import Count, Avg

# one number for the whole set
Book.objects.aggregate(avg_pages=Avg("pages"))

# a count attached to each author
Author.objects.annotate(num_books=Count("book"))

Key point: The one-line rule the question needs: aggregate collapses the set, annotate adds per-row. Give an example of each.

Q27. What are Q objects and F expressions used for?

Q objects build complex query conditions with OR, AND, and NOT, which plain keyword filters can't express because keyword arguments only combine with AND. You wrap conditions in Q() and join them with | and &.

F expressions reference a model field's value inside a query or update, so the database does the arithmetic without loading the value into Python. That makes field-to-field comparisons and atomic increments possible.

python
from django.db.models import Q, F

# OR condition
Book.objects.filter(Q(title__icontains="django") | Q(title__icontains="python"))

# atomic increment at the database
Book.objects.filter(pk=1).update(views=F("views") + 1)

Key point: The F-expression increment is the interviewer's favorite: it avoids a read-modify-write race. Mention that it's atomic.

Q28. How do you manage database transactions in Django?

By default each query autocommits. To group operations so they succeed or fail together, wrap them in transaction.atomic() as a context manager or decorator: if any operation inside raises, the whole block rolls back.

You can also set ATOMIC_REQUESTS to wrap each request in a transaction. For long operations, use select_for_update() to lock rows and avoid lost updates under concurrency.

python
from django.db import transaction

with transaction.atomic():
    account.balance -= 100
    account.save()
    ledger.record(-100)
    # if ledger.record raises, the balance change rolls back too

Q29. How do authentication and authorization work in Django?

Authentication verifies who a user is: Django's auth system handles login, logout, password hashing (PBKDF2 by default), and sessions, exposing request.user. Authorization decides what that user can do: the permissions and groups framework, plus checks like login_required and permission_required.

You extend the default User model when you need extra fields, using a custom user model set early via AUTH_USER_MODEL. For APIs, Django REST Framework layers token, session, or JWT authentication on top.

Key point: Naming AUTH_USER_MODEL and saying to set it before the first migration signals you've been burned by changing it late, which is genuinely hard to reverse.

Q30. How do sessions work in Django?

Django stores a session ID in a cookie on the client and keeps the actual session data server-side, keyed by that ID. By default the data lives in the database, but you can back sessions with the cache, files, or signed cookies.

You read and write session data through request.session, which behaves like a dict. Sessions carry things like the logged-in user and short-lived flags across requests without exposing the data to the browser.

python
def add_to_cart(request, item_id):
    cart = request.session.get('cart', [])
    cart.append(item_id)
    request.session['cart'] = cart
    return redirect('cart')

Q31. What is a custom model manager and why write one?

A manager is the interface through which models run queries; objects is the default one. A custom manager lets you add reusable query methods or change the default queryset, so common filters live in one place instead of being repeated across views.

A frequent use is a manager that returns only published or active records, so callers write Article.published.all() instead of remembering the filter every time.

python
class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(status="published")

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

Article.published.all()

Q32. How does caching work in Django?

Django has a layered cache framework. The per-site and per-view caches store whole responses; the low-level cache API (cache.get, cache.set) stores arbitrary values; and template fragment caching stores parts of a page. Backends include Redis, Memcached, the database, and local memory.

The rule is cache the expensive and stable, and invalidate deliberately. Cache keys, timeouts, and a plan for busting stale entries matter more than the backend choice.

python
from django.core.cache import cache

def expensive_report():
    result = cache.get("monthly_report")
    if result is None:
        result = build_report()          # slow
        cache.set("monthly_report", result, timeout=3600)
    return result

Key point: The follow-up is always invalidation. Saying caching is easy but invalidation is the hard part shows you've run this in production.

Q33. What is Django REST Framework and what does a serializer do?

Django REST Framework (DRF) is the standard toolkit for building web APIs on top of Django. It adds serializers, viewsets, routers, authentication classes, and a browsable API. A serializer converts model instances and querysets into JSON for responses and validates and converts incoming JSON back into Python objects.

ModelSerializer generates fields directly from a model, similar to how ModelForm works. It handles both directions: serialization out and validated deserialization in.

python
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ["id", "title", "published"]

# instance -> JSON, and validated JSON -> instance

Key point: If the role mentions APIs, this is where the interview lives. Know serializer validation and the difference between a Serializer and a ModelSerializer.

Watch a deeper explanation

Video: Build a Django REST API with the Django Rest Framework. Complete Tutorial. (CodingEntrepreneurs, YouTube)

Q34. What are viewsets and routers in DRF?

A viewset groups the logic for a set of related endpoints (list, retrieve, create, update, destroy) into one class, so you don't write a separate view per action. ModelViewSet gives you all of CRUD from a queryset and a serializer.

A router then generates the URL patterns for a viewset automatically, wiring the standard REST routes. Together they cut a lot of boilerplate for resource-style APIs.

python
from rest_framework import viewsets, routers

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

router = routers.DefaultRouter()
router.register(r"books", BookViewSet)
urlpatterns = router.urls

Q35. What is a context processor?

A context processor is a function that injects variables into the context of every template automatically, so you don't pass the same data from each view. Django ships several: request, auth (which adds user), and messages.

You write your own for site-wide values like a company name, feature flags, or a cart count. It returns a dict that gets merged into every template's context. Keep it cheap, since it runs on every render.

python
def site_settings(request):
    return {
        "site_name": "Hyring",
        "support_email": "help@example.com",
    }
# add the dotted path to TEMPLATES['OPTIONS']['context_processors']

Q36. What does the Meta class in a model configure?

The inner Meta class holds model-level options that aren't fields: ordering for a default sort, db_table to override the table name, unique_together or constraints for multi-column uniqueness, verbose_name for display, and indexes for database indexes.

It's how you tune behavior and performance without adding columns. Adding an index on a frequently filtered field, or a default ordering, are common Meta uses.

python
class Book(models.Model):
    title = models.CharField(max_length=200)
    published = models.DateField()

    class Meta:
        ordering = ["-published"]
        indexes = [models.Index(fields=["published"])]
        constraints = [
            models.UniqueConstraint(fields=["title"], name="unique_title"),
        ]

Q37. What do get_object_or_404 and get_list_or_404 do?

get_object_or_404 runs a get() and, instead of raising DoesNotExist, raises Http404 when nothing matches, so Django returns a clean 404 page. get_list_or_404 does the same for a filter that returns an empty list.

They remove the repetitive try/except around lookups in views and turn a missing record into the correct HTTP response automatically.

python
from django.shortcuts import get_object_or_404

def book_detail(request, pk):
    book = get_object_or_404(Book, pk=pk)
    return render(request, "detail.html", {"book": book})

Q39. What are the on_delete options on a ForeignKey?

on_delete tells Django what to do to rows that reference a record when that record is deleted. CASCADE deletes them too, PROTECT blocks the delete and raises, SET_NULL sets the reference to NULL (requires null=True), SET_DEFAULT uses the field's default, and DO_NOTHING leaves it to the database.

The choice is a data-integrity decision. CASCADE for owned children, PROTECT for references you don't want silently destroyed, SET_NULL when the link is optional.

OptionEffect on delete
CASCADEDelete the referencing rows too
PROTECTBlock the delete, raise ProtectedError
SET_NULLSet the FK to NULL (needs null=True)
SET_DEFAULTSet the FK to the field default
DO_NOTHINGTake no action, defer to the database

Key point: on_delete is required with no default, on purpose. Explaining CASCADE versus PROTECT as a data-safety call is the answer they want.

Q40. How do you test a Django application?

Django's test framework builds on unittest and adds a TestCase that wraps each test in a transaction rolled back afterward, plus a test client that simulates requests. You get a fresh test database, fixtures or factories for data, and assertions like assertContains and assertRedirects.

Many teams run tests with pytest and pytest-django for its fixtures and cleaner syntax. Test models, views, and API endpoints, and mock external services so tests stay fast and deterministic.

python
from django.test import TestCase
from django.urls import reverse

class BookViewTests(TestCase):
    def test_list_returns_200(self):
        response = self.client.get(reverse("book-list"))
        self.assertEqual(response.status_code, 200)

Q41. How do bulk_create and update() work, and what do they skip?

bulk_create() inserts many objects in one query instead of one INSERT per object, and update() on a queryset writes a change to every matching row in a single UPDATE. Both are far faster than looping and calling save() per instance.

The catch that trips people: neither calls the model's save() method or fires pre_save and post_save signals, because they bypass the per-instance path. Logic living in save() or a signal won't run, so side effects you rely on silently don't happen.

python
Book.objects.bulk_create([
    Book(title="A"),
    Book(title="B"),
])  # one INSERT, no save() or signals

Book.objects.filter(published__year=2025).update(archived=True)  # one UPDATE

Key point: The 'skips save() and signals' detail is exactly what this question is testing. It's a real production bug source, so the key signal is it.

Back to question list

Django Interview Questions for Experienced Developers

Experienced19 questions

advanced rounds probe internals, design judgment, and production scars. Expect every answer here to draw a follow-up.

Q42. Walk through the full request/response cycle in Django.

A request hits the server (Gunicorn or Uvicorn), which calls Django through WSGI or ASGI. Django builds an HttpRequest, then runs it down the middleware chain. URL resolution matches the path to a view. The view runs, usually touching the ORM and rendering a template or serializing data, and returns an HttpResponse.

The response travels back up the middleware chain, where components can modify it, and Django hands it to the server to send. Knowing where middleware, URL resolution, and the view sit in that order is what this question checks.

Key point: Draw the chain out loud: server, middleware in, URL resolver, view, response, middleware out. Missing the two-way middleware pass is the common gap.

Watch a deeper explanation

Video: Python Django Crash Course (Traversy Media, YouTube)

Q43. How do you scale a Django application?

Scale in layers. At the database, add indexes, fix N+1 queries, use read replicas, and add connection pooling. At the application, run multiple stateless worker processes behind a load balancer and keep sessions in a shared store. Add caching (Redis) for hot reads, and move slow work off the request into a task queue like Celery.

The order matters: profile to find the real bottleneck first, then apply the cheapest fix that moves it. Most Django scaling problems are database problems wearing an application costume.

Key point: The production signal is saying most scaling issues are database-bound and that you'd measure before adding servers. Reaching for more machines first indicates junior.

Q44. How do you handle background and asynchronous tasks?

For work that shouldn't block the request, offload it to a task queue. Celery with a broker like Redis or RabbitMQ is the common choice: the view enqueues a task and returns immediately, and a separate worker process runs it. Use it for emails, report generation, image processing, and third-party API calls.

For scheduled jobs, Celery Beat or a cron-driven management command works. Django's own async views and ASGI help with concurrent I/O within a request, but they don't replace a queue for durable, retryable background work.

python
from celery import shared_task

@shared_task
def send_welcome_email(user_id):
    user = User.objects.get(pk=user_id)
    email.send(user.email, template="welcome")

# in a view, enqueue and return fast
send_welcome_email.delay(user.id)

Q45. How do you implement a custom user model, and what breaks if you add it late?

Set AUTH_USER_MODEL to your model and subclass AbstractUser (to extend the default) or AbstractBaseUser (to build from scratch, defining the auth fields yourself). Do it at the very start of a project, before the first migration.

Adding it late is painful because the initial migrations already reference the built-in User with foreign keys and permissions. Migrating an existing user table to a new model means data migrations and untangling those references, which is why the advice is always to set the custom user model on day one.

Key point: The whole point of this question is the 'set it early' lesson. Candidates who've felt the late-migration pain answer it with feeling.

Q46. When would you drop from the ORM to raw SQL?

When a query is complex enough that the ORM makes it awkward or inefficient: heavy window functions, recursive CTEs, database-specific features, or a hand-tuned query that outperforms what the ORM generates. Django gives you Manager.raw() for model-mapped raw queries and connection.cursor() for arbitrary SQL.

The discipline: still parameterize (pass params, never format strings) to stay safe from injection, and keep raw SQL rare and documented. Most of the time extra_related, annotate, and Subquery keep you inside the ORM.

python
from django.db import connection

with connection.cursor() as cursor:
    cursor.execute(
        "SELECT author_id, COUNT(*) FROM books_book WHERE published_id = %s GROUP BY author_id",
        [year_id],   # parameterized, not string-formatted
    )
    rows = cursor.fetchall()

Key point: Say you still parameterize raw SQL. Concatenating user input into a raw query is the one way to reintroduce injection, and the key signal is that.

Q47. What security protections does Django provide, and what must you still do?

Out of the box Django parameterizes ORM queries (SQL injection), auto-escapes template output (XSS), requires CSRF tokens on unsafe methods, hashes passwords with a strong algorithm, and offers clickjacking protection via X-Frame-Options middleware.

What's on you: set DEBUG=False and a real ALLOWED_HOSTS in production, keep the SECRET_KEY out of the repo, run over HTTPS with SECURE_SSL_REDIRECT and HSTS, set secure and httponly cookie flags, and validate file uploads. The framework gives defaults; production hardening is your job.

  • SQL injection: ORM parameterizes queries automatically.
  • XSS: templates auto-escape variables unless you mark them safe.
  • CSRF: tokens required on POST, PUT, PATCH, DELETE.
  • You add: DEBUG=False, HTTPS/HSTS, secure cookies, ALLOWED_HOSTS, secret management.

Key point: List the built-in defenses, then pivot to what you configure. Naming DEBUG=False and HSTS is what separates 'I read the docs' from 'I've deployed this'.

Q48. How do you diagnose and fix a slow Django page?

Measure first: Django Debug Toolbar or query logging shows the SQL, counts, and timings for a page. Look for N+1 loops, missing indexes on filtered or ordered columns, queries pulling more columns or rows than needed, and duplicate queries that caching could remove.

Then fix in order of impact: add select_related/prefetch_related, add indexes, use only() or values() to trim columns, paginate large result sets, and cache expensive stable reads. Confirm each fix with the same measurement.

Key point: in ORM clothing. Observe, hypothesize, fix, confirm. Jumping to a fix without measuring first is the failure mode.

Q49. When would you use a signal versus overriding save()?

Override save() when the logic is intrinsic to that model and should run wherever it's saved: normalizing a field, computing a derived value. It's explicit and easy to find. Use a signal when the reacting code lives in a different app or shouldn't know about the sender, so the two stay decoupled.

The trade-off is clarity versus coupling. save() keeps behavior visible on the model; signals scatter it but let unrelated apps hook in. Note that bulk operations like bulk_create and queryset update() skip both save() and per-instance signals, which surprises people.

Key point: The bulk_create/update caveat is the senior detail here. these skip save() and.

Q50. How do you prevent race conditions on concurrent database writes?

Two main tools. select_for_update() locks the selected rows inside a transaction so another transaction can't modify them until yours commits, which prevents lost updates on read-modify-write patterns. F expressions push the update into the database as one atomic operation, avoiding the read entirely.

For uniqueness under concurrency, rely on a database unique constraint and handle IntegrityError rather than checking-then-inserting, because the check-then-act window is exactly where the race lives.

python
from django.db import transaction

with transaction.atomic():
    account = Account.objects.select_for_update().get(pk=pk)
    account.balance -= amount
    account.save()
# other writers wait until this transaction commits

Key point: Naming both select_for_update and the F-expression atomic increment, and when each fits, is the mark of someone who has hit a real race in production.

Q51. How do you structure settings and secrets across environments?

Split settings into a base module plus per-environment overrides (base, dev, production), selected by DJANGO_SETTINGS_MODULE, or use one file that reads environment variables. Deployment-specific values (database URL, allowed hosts, debug) come from the environment, and secrets come from the platform's secret manager, never the repo.

The anti-patterns to name: a single settings.py with hardcoded credentials, DEBUG left True, and the SECRET_KEY committed to git. Reading config once at startup into validated values, rather than scattered os.environ reads, keeps it testable.

Q52. How do database routers and multiple databases work in Django?

You define connections in the DATABASES setting and write a database router class that tells Django which connection to use for reads, writes, and migrations of a given model. A common setup routes writes to a primary and reads to replicas to spread load.

You can also force a specific database per query with using(). The catch is that cross-database relations and transactions don't span connections, so the router design has to respect where related data lives.

python
class PrimaryReplicaRouter:
    def db_for_read(self, model, **hints):
        return "replica"
    def db_for_write(self, model, **hints):
        return "default"

# force a connection for one query
Book.objects.using("replica").all()

Q53. What is the contenttypes framework and when do you use generic relations?

The contenttypes framework keeps a registry of every model in the project, so code can refer to a model generically at runtime. Generic relations build on it to let one model relate to any other model, using a ContentType foreign key plus an object id.

Use it for cross-cutting features that attach to many models: comments, tags, likes, or an audit log that can reference any record. The trade-off is that generic foreign keys can't be joined as cleanly as real foreign keys, so use them where the flexibility genuinely pays off.

python
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class Comment(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    target = GenericForeignKey("content_type", "object_id")

Q54. What is the state of async support in Django?

Django supports asynchronous views, middleware, and an async ORM interface, running under ASGI. Async views help when a request waits on multiple slow I/O operations you can run concurrently, like several external API calls.

The limits worth stating: parts of the stack are still synchronous, mixing sync and async carries overhead, and a blocking call inside an async view stalls the event loop. For most CPU work or durable background jobs, a task queue still beats async views.

python
from django.http import JsonResponse

async def dashboard(request):
    profile = await get_profile(request.user.id)
    stats = await get_stats(request.user.id)
    return JsonResponse({"profile": profile, "stats": stats})

Key point: The honest answer includes the caveats: sync bits remain, and async is not a substitute for Celery. Overselling async is a common trap.

Q55. How do you run migrations safely in production?

Treat schema changes as a deployment concern. Make them backward-compatible so old and new code can run together during a rolling deploy: add columns as nullable or with defaults first, deploy code that writes them, backfill data in a separate step, then enforce constraints in a later migration.

Watch for locks: adding an index or a NOT NULL column can lock a large table. Use techniques like creating indexes concurrently on PostgreSQL, run heavy data migrations in batches off the request path, and always have a rollback plan.

  • Keep each migration backward-compatible for zero-downtime rolling deploys.
  • Split add-column, backfill, and add-constraint into separate steps.
  • Beware table locks on large tables; batch data migrations.
  • Test the migration on a production-sized copy before running it live.

A safe zero-downtime schema change

1Add nullable column
additive migration old code tolerates
2Deploy code that writes it
both old and new rows now populate
3Backfill in batches
fill existing rows off the request path
4Add the constraint
enforce NOT NULL or uniqueness last

Each step is deployable on its own, so a rolling deploy never has code and schema out of sync.

Q56. When do you use middleware versus a view decorator versus a mixin?

Middleware for behavior that applies to every request or a broad set of them: security headers, request logging, tenant resolution. A decorator for per-view opt-in behavior on function-based views: login_required, cache_page, rate limiting one endpoint. A mixin for shared behavior across class-based views, like a permission check baked into several views.

The choice is about scope and granularity. Middleware is global and ordered, decorators and mixins are targeted. Putting endpoint-specific logic in middleware, or global concerns in a decorator repeated everywhere, is the smell to avoid.

ToolScopeTypical use
MiddlewareEvery requestHeaders, logging, auth, sessions
DecoratorOne function viewlogin_required, cache_page
MixinA set of class-based viewsShared permission or context logic

Q57. What does a production Django deployment stack look like?

A typical stack runs Django under an application server (Gunicorn for WSGI, Uvicorn or Daphne for ASGI) with several worker processes, behind a reverse proxy like Nginx that serves static files and terminates TLS. A CDN fronts static and media assets, PostgreSQL is the database, and Redis handles cache and the Celery broker.

The app runs statelessly so you can scale workers horizontally, with sessions and cache in shared stores. Configuration comes from environment variables, secrets from a manager, and the whole thing is usually packaged as a container image deployed behind a load balancer.

Key point: Naming Gunicorn/Uvicorn plus Nginx and why (runserver is dev-only, the proxy serves static and TLS) is the experienced answer. Vague answers stop at 'deploy it to a server'.

Q58. What are common Django gotchas experienced developers watch for?

A handful recur. Mutable defaults and mutating querysets in place; queryset laziness causing a query to fire at an unexpected moment; N+1 loops hidden behind template attribute access; bulk_create and update() skipping save() and signals; changing AUTH_USER_MODEL after migrations; and DEBUG left True in production leaking data.

Also: comparing a queryset's truthiness runs a query, timezone-naive datetimes when USE_TZ is on, and relying on signal side effects that don't run for bulk operations. Knowing these is the difference between writing Django and debugging it at 2am.

Key point: This open-ended question rewards specifics. Two or three concrete gotchas with the reason each bites beats a generic 'be careful with the ORM'.

Q59. How do you handle authentication and permissions in a DRF API?

DRF separates authentication (who you are) from permissions (what you can do). Authentication classes identify the request: SessionAuthentication for browser clients, TokenAuthentication for a stored token, and JWT via a package like SimpleJWT for stateless tokens. Permission classes then gate access: IsAuthenticated, IsAdminUser, or a custom class checking object ownership.

You set defaults globally in REST_FRAMEWORK and override per view. For stateless mobile or single-page clients, JWT is common; for server-rendered sessions, session auth reuses Django's login. Object-level permissions handle 'you can edit only your own records'.

python
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet

class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.queryset.filter(owner=self.request.user)  # object scoping

Key point: Separating authentication from permission classes, and naming object-level checks for ownership, is the answer that indicates real API experience.

Q60. When would you choose session authentication over JWT for a Django API?

Session auth stores state server-side and sends a session cookie, so you can revoke a session instantly by deleting it, and it pairs naturally with Django's CSRF protection for browser clients. JWT is stateless: the token carries claims and the server verifies a signature without a lookup, which scales across services but makes instant revocation harder.

Choose sessions for first-party web apps where the cookie and CSRF story is simplest, and JWT for mobile clients, third-party API consumers, or multi-service setups where stateless verification matters. The revocation trade-off is the deciding factor to name.

Session authJWT
StateServer-sideStateless (in the token)
RevocationInstant (delete session)Harder (needs a blocklist)
Best fitFirst-party web appsMobile, third-party, multi-service

Key point: The revocation difference is the senior point. Saying JWT trades easy revocation for stateless scale shows you've weighed it, not just picked the trendy option.

Back to question list

Why Django? Django vs Flask, FastAPI, and Express

Django wins when you want a full stack of decisions made for you: an ORM, migrations, an admin, auth, and security defaults that let a small team ship a real application in days. It trades flexibility for convention, so you accept its structure in return for speed and fewer choices to get wrong. Flask and FastAPI stay minimal and let you assemble your own pieces, which fits small services and API-only work. Express plays the same minimal role in the Node ecosystem. Knowing where each fits, and saying it out loud, is itself an interview signal: it shows you pick tools on merits, not habit.

FrameworkLanguageStyleBest at
DjangoPythonBatteries included, MVTFull apps with admin, auth, ORM out of the box
FlaskPythonMinimal, you assemble partsSmall services, custom stacks
FastAPIPythonMinimal, async-first, typedHigh-throughput APIs with auto docs
ExpressJavaScriptMinimal, middleware-basedNode APIs and full-stack JS teams

How to Prepare for a Django Interview

Prepare in layers, and practice out loud. Most Django rounds move from concept questions to live coding to a design or debugging discussion, so rehearse each stage rather than only reading answers.

  • Master your tier's concepts until you can explain them without notes, then read one tier up for the stretch questions.
  • Build one small project end to end (model, view, template or serializer, URL) so the request cycle is muscle memory.
  • Practice reasoning about querysets out loud: what SQL runs, how many queries, where N+1 hides.
  • Take the quiz on this page to find weak spots, then revisit those questions before the real round.

The typical Django interview flow

1Recruiter or phone screen
background, projects, a few concept checks
2Technical concepts
MVT, the ORM, migrations, middleware, forms, security defaults
3Live coding
write a model, a view, or a queryset and explain it
4Design or debugging
scaling, caching, N+1 queries, trade-offs, follow-ups

Earlier rounds increasingly run as AI coding interviews. The concepts on this page are what gets probed at every stage.

Test Yourself: Django Quiz

Ready to test your Django knowledge?

10 questions, about 6 minutes. Score 70% or higher to earn a shareable certificate.

10 questions Instant feedback Free certificate on 70%+

Frequently  Asked  Questions

Which Django topics should I prioritize before a technical round?

Prioritize the areas that change real decisions: fundamentals, practical tasks, debugging, trade-offs, and evidence. The highest-value questions are tied to a project example, a validation check, or a failure mode.

Are these questions enough to pass a Django interview?

They cover the question-answer portion well, but most Django rounds also include live coding: writing a model or a view while explaining your thinking. building a small feature end to end is the practice path. Our AI coding interview prep guide covers that format, including how automated evaluation reads your process.

Do I need to know Django REST Framework?

For most backend roles, yes. DRF is the standard way Django exposes APIs, so expect questions on serializers, viewsets, and authentication. If the job is server-rendered pages only, focus on views, templates, and forms instead. When unsure, ask the interviewer which the role uses and answer for that.

Which Django version do these answers assume?

Modern Django, versions 4 and 5, which share the same core model. Nothing here depends on a version-specific feature that would trip you up in an interview. When a detail is version-sensitive, say which version you're describing; interviewers respect that precision.

How long does it take to prepare for a Django interview?

If you use Django at work or in study, one to two weeks of an hour a day covers this bank with practice runs. Starting colder, plan three to four weeks and build a small project daily; reading answers without writing code is how preparation quietly fails.

Is there a way to test my Django knowledge?

Yes. The quiz on this page scores you as you go and explains every answer, so you find your weak spots fast. Pass the threshold and you can download a shareable certificate with your name and score, free and with no sign-up. It's the quickest way to check yourself before the real round.

From the team that builds coding interviews

Hyring builds the AI Coding Interviewer that runs live technical rounds in 20+ languages for 5,000+ hiring teams. These Django questions and scoring notes reflect what actually gets asked and evaluated inside the interviews we host.

See how the AI Coding Interviewer works

Sources

Adithyan RKWritten by Adithyan RK
Surya N
Fact-checked by Surya N
Published on: 9 May 2026Last updated: 16 Jun 2026
Share: