Domande Colloquio Django: ORM, Middleware e DRF in Profondità
Guida completa alle domande colloquio Django 2026: ottimizzazione ORM, architettura middleware e pattern Django REST Framework con esempi di codice.

Le domande colloquio Django si concentrano su tre pilastri fondamentali che distinguono i candidati senior dagli altri: la padronanza dell'ORM, l'architettura middleware e i design pattern di Django REST Framework (DRF). Questa guida analizza le domande esatte che i responsabili delle assunzioni pongono nel 2026, con esempi di codice pronti per la produzione utilizzando Django 5.2 LTS e DRF 3.17.
I colloqui Django raramente si soffermano sulle operazioni CRUD di base. L'attenzione si è spostata sull'ottimizzazione dei QuerySet (select_related vs prefetch_related), sulla progettazione di middleware personalizzati e sulle performance dei serializer DRF. I candidati in grado di spiegare le query N+1 e scrivere viewset efficienti superano costantemente chi conosce solo le generic view.
Domande Colloquio Django ORM: Ottimizzazione dei QuerySet
La domanda più frequente sui colloqui Django ORM riguarda il problema N+1. Dato un modello con relazioni foreign key, i candidati devono dimostrare quando utilizzare select_related rispetto a prefetch_related.
Il problema N+1 rappresenta uno degli antipattern più insidiosi nello sviluppo Django. Si verifica quando il codice esegue una query per recuperare un elenco di oggetti e poi, per ciascun oggetto, esegue una query aggiuntiva per recuperare i dati correlati. Con 100 oggetti, questo comporta 101 query invece di 2.
# models.py
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=200)
founded_year = models.IntegerField()
class Developer(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="developers")
skills = models.ManyToManyField("Skill", related_name="developers")
class Skill(models.Model):
name = models.CharField(max_length=100)
category = models.CharField(max_length=50)La distinzione tra select_related e prefetch_related costituisce una delle competenze fondamentali che ogni sviluppatore Django deve padroneggiare. Il primo utilizza un JOIN SQL ed è ottimale per relazioni ForeignKey e OneToOneField, dove esiste un solo oggetto correlato. Il secondo esegue query separate ed è ideale per relazioni ManyToMany o reverse ForeignKey, dove esistono molteplici oggetti correlati.
# queries.py — Correct approach for ForeignKey (single object)
developers = Developer.objects.select_related("company").all()
# Generates ONE SQL query with JOIN
# SELECT developer.*, company.* FROM developer INNER JOIN company ...
# Correct approach for ManyToMany (multiple objects)
developers = Developer.objects.prefetch_related("skills").all()
# Generates TWO SQL queries:
# 1. SELECT * FROM developer
# 2. SELECT * FROM skill INNER JOIN developer_skills WHERE developer_id IN (...)Durante i colloqui tecnici, i selezionatori spesso presentano scenari complessi dove è necessario combinare entrambi gli approcci. La capacità di analizzare la struttura dei modelli e determinare la strategia ottimale di fetching dimostra una comprensione profonda del funzionamento interno di Django.
ORM Avanzato: Manager Personalizzati e Concatenamento QuerySet
Le domande sui manager personalizzati testano la capacità del candidato di estendere le funzionalità base di Django ORM. Un manager personalizzato permette di incapsulare logiche di query complesse e riutilizzabili, mantenendo il codice delle view pulito e manutenibile.
# managers.py
from django.db import models
from django.utils import timezone
class ActiveDeveloperQuerySet(models.QuerySet):
def active(self):
"""Filter developers who logged in within the last 30 days."""
cutoff = timezone.now() - timezone.timedelta(days=30)
return self.filter(last_login__gte=cutoff)
def senior(self):
"""Filter developers with 5+ years of experience."""
return self.filter(years_experience__gte=5)
def by_skill(self, skill_name):
"""Filter developers by a specific skill."""
return self.filter(skills__name=skill_name)
class ActiveDeveloperManager(models.Manager):
def get_queryset(self):
return ActiveDeveloperQuerySet(self.model, using=self._db)
def active(self):
return self.get_queryset().active()Il pattern del QuerySet personalizzato garantisce che ogni metodo restituisca un nuovo QuerySet, permettendo il concatenamento fluido delle operazioni. Questo approccio segue il principio della composizione, dove filtri complessi vengono costruiti combinando operazioni semplici e riutilizzabili.
# usage.py — QuerySet chaining in action
# This works because each method returns a QuerySet
senior_python_devs = (
Developer.active_objects # custom manager
.active() # ActiveDeveloperQuerySet method
.senior() # chains another QuerySet method
.by_skill("Python") # chains a third method
.select_related("company") # standard QuerySet method still works
)I candidati devono comprendere che i QuerySet sono lazy: nessuna query viene eseguita finché il QuerySet non viene valutato. Questa caratteristica permette di costruire query complesse in modo incrementale senza penalizzazioni di performance.
Django 5.2 ha introdotto CompositePrimaryKey, una funzionalità attesa da tempo per modelli che necessitano di chiavi primarie multi-colonna. Le domande su questa feature stanno diventando più comuni, specialmente per candidati che lavorano con database legacy o schemi di data warehouse.
Domande Colloquio Django Middleware: Pipeline Request-Response
La comprensione dell'architettura middleware rappresenta un indicatore chiave della seniority di uno sviluppatore Django. Il middleware opera come una serie di layer che processano ogni richiesta HTTP in entrata e ogni risposta in uscita, seguendo un pattern a cipolla dove la richiesta attraversa ogni layer in sequenza.
I selezionatori frequentemente chiedono ai candidati di implementare middleware per logging, autenticazione, rate limiting o manipolazione delle response. La struttura base del middleware Django moderno utilizza una classe con i metodi __init__ e __call__.
# middleware.py
import time
import logging
from django.http import JsonResponse
logger = logging.getLogger(__name__)
class RequestTimingMiddleware:
"""Logs the time taken to process each request."""
def __init__(self, get_response):
self.get_response = get_response # next middleware or view
def __call__(self, request):
start_time = time.monotonic()
response = self.get_response(request) # passes to next layer
duration_ms = (time.monotonic() - start_time) * 1000
logger.info(
"method=%s path=%s status=%d duration=%.2fms",
request.method,
request.path,
response.status_code,
duration_ms,
)
return responseUn aspetto cruciale che viene spesso testato riguarda la capacità del middleware di cortocircuitare la pipeline. Quando un middleware restituisce direttamente una response invece di chiamare get_response, i layer successivi e la view non vengono mai eseguiti. Questo pattern è fondamentale per implementare controlli di sicurezza e rate limiting.
# middleware.py — Rate limiting with short-circuit
from django.core.cache import cache
class RateLimitMiddleware:
"""Blocks requests exceeding 100 per minute per IP."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
ip = request.META.get("REMOTE_ADDR")
cache_key = f"rate_limit:{ip}"
request_count = cache.get(cache_key, 0)
if request_count >= 100:
return JsonResponse( # short-circuits — view never executes
{"error": "Rate limit exceeded. Try again in 60 seconds."},
status=429,
)
cache.set(cache_key, request_count + 1, timeout=60)
return self.get_response(request)Hook del Middleware: process_view, process_exception e process_template_response
Oltre ai metodi base, Django middleware supporta hook specializzati che intervengono in punti specifici del ciclo di vita della richiesta. La conoscenza di questi hook distingue i candidati senior che hanno lavorato su applicazioni Django complesse.
Il metodo process_view viene invocato dopo la risoluzione dell'URL ma prima dell'esecuzione della view, permettendo di ispezionare o modificare i parametri passati alla view. Il metodo process_exception intercetta le eccezioni sollevate dalle view, abilitando logging centralizzato o gestione personalizzata degli errori. Infine, process_template_response permette di modificare il contesto dei template prima del rendering.
# middleware.py — Full middleware with all hooks
class AuditMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_view(self, request, view_func, view_args, view_kwargs):
"""Called after URL resolution, before the view executes."""
logger.info("Calling view: %s", view_func.__name__)
return None # returning None continues normal processing
def process_exception(self, request, exception):
"""Called only if the view raises an exception."""
logger.error("View exception: %s", exception, exc_info=True)
return None # returning None lets Django's default handling proceed
def process_template_response(self, request, response):
"""Called if the response has a render() method (TemplateResponse)."""
response.context_data["audit_timestamp"] = time.time()
return response # must return a response with render()Durante i colloqui, viene spesso chiesto l'ordine di esecuzione degli hook. La sequenza procede dall'alto verso il basso nella lista MIDDLEWARE per __call__ e process_view, mentre process_exception e process_template_response procedono dal basso verso l'alto, permettendo ai middleware più esterni di processare per ultimi.
Pronto a superare i tuoi colloqui su Django?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Domande Colloquio DRF: Performance dei Serializer
Django REST Framework costituisce lo standard de facto per la costruzione di API REST in Django. Le domande sui serializer DRF si concentrano sulla corretta gestione delle relazioni nested e sull'ottimizzazione delle query per evitare il famigerato problema N+1 a livello di API.
I serializer nested rappresentano un pattern comune ma potenzialmente problematico. Senza la corretta ottimizzazione del QuerySet nella view, ogni oggetto serializzato può generare query aggiuntive per recuperare gli oggetti correlati.
# serializers.py
from rest_framework import serializers
from .models import Developer, Company, Skill
class SkillSerializer(serializers.ModelSerializer):
class Meta:
model = Skill
fields = ["name", "category"]
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ["name", "founded_year"]
class DeveloperSerializer(serializers.ModelSerializer):
company = CompanySerializer(read_only=True) # nested FK
skills = SkillSerializer(many=True, read_only=True) # nested M2M
class Meta:
model = Developer
fields = ["id", "name", "company", "skills"]La chiave per performance ottimali risiede nel metodo get_queryset della view. Applicando select_related per le ForeignKey e prefetch_related per le ManyToMany, il numero di query rimane costante indipendentemente dal numero di oggetti restituiti.
# views.py
from rest_framework import viewsets
from .models import Developer
from .serializers import DeveloperSerializer
class DeveloperViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = DeveloperSerializer
def get_queryset(self):
return (
Developer.objects
.select_related("company") # JOIN for FK
.prefetch_related("skills") # separate query for M2M
.order_by("-id")
)DRF: Permessi Personalizzati e Autenticazione
La sicurezza delle API rappresenta un tema centrale nei colloqui DRF. I candidati devono dimostrare la capacità di implementare permessi object-level che controllano l'accesso non solo all'endpoint ma anche ai singoli oggetti.
Il sistema di permessi DRF opera su due livelli: has_permission controlla l'accesso generale all'endpoint, mentre has_object_permission verifica l'accesso al singolo oggetto nelle operazioni di retrieve, update e delete.
# permissions.py
from rest_framework.permissions import BasePermission
class IsOwnerOrAdmin(BasePermission):
"""
Object-level permission:
- Admin users can access any object
- Regular users can only access objects they own
"""
message = "Access restricted to the object owner or admin users."
def has_object_permission(self, request, view, obj):
if request.user.is_staff:
return True
# Assumes the model has an 'owner' field pointing to User
return obj.owner == request.userL'implementazione corretta dei permessi richiede sia il controllo object-level che il filtraggio del QuerySet. Questa doppia protezione garantisce che gli utenti non possano accedere a oggetti non autorizzati né tramite accesso diretto né tramite la lista.
# views.py — Applying custom permissions
from rest_framework import viewsets, permissions
from .permissions import IsOwnerOrAdmin
class ProjectViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin]
def get_queryset(self):
# Non-admin users only see their own projects
if self.request.user.is_staff:
return Project.objects.all()
return Project.objects.filter(owner=self.request.user)
def perform_create(self, serializer):
serializer.save(owner=self.request.user) # auto-assign ownerAffidarsi esclusivamente a has_object_permission senza filtrare il queryset lascia l'endpoint lista non protetto. Combinare sempre i permessi object-level con un get_queryset filtrato per applicare il controllo accessi sia sulle view lista che su quelle di dettaglio.
DRF: Pattern di Throttling e Paginazione
Il throttling protegge le API da abusi e garantisce una distribuzione equa delle risorse. DRF fornisce classi di throttling predefinite che possono essere configurate globalmente o applicate a specifiche view.
La paginazione cursor-based rappresenta l'approccio più performante per dataset di grandi dimensioni. A differenza della paginazione offset-based, che diventa progressivamente più lenta con offset elevati, la paginazione cursor mantiene performance costanti.
# settings.py — Production DRF configuration
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.AnonRateThrottle",
"rest_framework.throttling.UserRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {
"anon": "20/minute",
"user": "200/minute",
},
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.CursorPagination",
"PAGE_SIZE": 25,
}La personalizzazione della paginazione cursor richiede la specifica di un campo di ordinamento unico e sequenziale. Il campo created_at rappresenta una scelta comune, garantendo risultati consistenti anche quando nuovi oggetti vengono aggiunti durante la navigazione.
# pagination.py — Custom cursor pagination for consistent ordering
from rest_framework.pagination import CursorPagination
class CreatedAtCursorPagination(CursorPagination):
page_size = 25
ordering = "-created_at"
cursor_query_param = "cursor"Conclusione: Prepararsi per il Colloquio Django
Affrontare con successo un colloquio Django richiede una preparazione mirata su questi argomenti chiave:
-
ORM Optimization: Padroneggiare
select_relatedeprefetch_relatedper eliminare le query N+1. Comprendere quando applicare ciascun metodo in base alla cardinalità delle relazioni. -
Custom Managers e QuerySet: Saper implementare QuerySet personalizzati che incapsulano logiche di business complesse mantenendo il concatenamento fluido delle operazioni.
-
Middleware Architecture: Comprendere la pipeline request-response, gli hook disponibili e la capacità di cortocircuitare la catena quando necessario.
-
DRF Serializer Performance: Ottimizzare i queryset nelle view per garantire che i serializer nested non generino query aggiuntive per ogni oggetto.
-
Sicurezza API: Implementare permessi object-level combinati con queryset filtrati per una protezione completa degli endpoint.
-
Throttling e Paginazione: Configurare rate limiting appropriato e scegliere la strategia di paginazione ottimale per il caso d'uso specifico.
La chiave del successo risiede non solo nella conoscenza teorica ma nella capacità di applicare questi concetti a scenari reali, dimostrando esperienza pratica con applicazioni Django in produzione.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Tag
Condividi
Articoli correlati

Django 5.2: Custom Middleware e Gestione dei Segnali per Colloqui Tecnici
Padroneggiare middleware e segnali in Django 5.2: pipeline middleware, middleware asincrono, pre_save/post_save signals e pattern comuni nei colloqui tecnici.

Django e Celery: Elaborazione Asincrona dei Task e Domande da Colloquio 2026
Guida completa a Django e Celery: configurazione, task asincroni, code, Celery Beat, monitoraggio e domande frequenti nei colloqui tecnici 2026.

Domande per colloqui Django e Python: Le Top 25 nel 2026
Le 25 domande piu comuni nei colloqui su Django e Python. ORM, view, middleware, DRF, signal e ottimizzazione con risposte dettagliate ed esempi di codice.