Preguntas de Entrevista Django y Python: Top 25 en 2026
Las 25 preguntas mas frecuentes en entrevistas de Django y Python. ORM, vistas, middlewares, DRF, signals y optimizacion con respuestas detalladas y ejemplos de codigo.

Las entrevistas de Django evaluan el dominio del framework web mas popular de Python, el conocimiento del ORM, la arquitectura MVT y la capacidad de construir APIs REST robustas. Esta guia cubre las 25 preguntas mas frecuentes, desde los fundamentos de Django hasta patrones avanzados de Django REST Framework.
Los entrevistadores valoran a los candidatos que explican las decisiones arquitectonicas de Django. Comprender por que el framework adopta ciertas convenciones (convencion sobre configuracion) marca una diferencia real en las entrevistas.
Fundamentos de Django
Pregunta 1: Describir la arquitectura MVT de Django
La arquitectura Model-View-Template (MVT) es la variacion de Django del patron MVC. El framework maneja la parte del controlador automaticamente, simplificando el desarrollo.
# models.py
# The Model represents data structure and business logic
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_at = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
"auth.User",
on_delete=models.CASCADE, # Deletes articles when author is deleted
related_name="articles" # Reverse access: user.articles.all()
)
class Meta:
ordering = ["-published_at"] # Default ordering
def __str__(self):
return self.title# views.py
# The View contains request processing logic
from django.shortcuts import render, get_object_or_404
def article_detail(request, pk):
# get_object_or_404 raises Http404 if the object doesn't exist
article = get_object_or_404(Article, pk=pk)
return render(request, "blog/article_detail.html", {"article": article})En MVT, Django actua como controlador enrutando las URLs hacia las vistas apropiadas a traves de urls.py. El Template se encarga de la presentacion HTML.
Pregunta 2: Cual es la diferencia entre un proyecto y una aplicacion en Django?
Un proyecto es la configuracion general (settings, URLs raiz, WSGI/ASGI). Una aplicacion es un modulo reutilizable con una unica responsabilidad. Un proyecto contiene multiples aplicaciones.
# Creating a project and an app
# django-admin startproject myproject
# python manage.py startapp blog
# settings.py
# Registering apps in the project
INSTALLED_APPS = [
"django.contrib.admin", # Admin interface
"django.contrib.auth", # Authentication
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Custom apps
"blog.apps.BlogConfig", # Blog app
"users.apps.UsersConfig", # Users app
]Cada aplicacion sigue el principio de responsabilidad unica y puede reutilizarse en diferentes proyectos.
Pregunta 3: Explicar el ciclo de vida de una peticion en Django
La peticion pasa por varias capas antes de llegar a la vista. Comprender este ciclo es esencial para la depuracion y la optimizacion.
# middleware.py
# Middlewares intercept every request/response
class RequestTimingMiddleware:
"""Middleware that measures processing time."""
def __init__(self, get_response):
self.get_response = get_response # Reference to the next middleware
def __call__(self, request):
import time
start = time.time()
# Request phase: before the view
response = self.get_response(request)
# Response phase: after the view
duration = time.time() - start
response["X-Request-Duration"] = f"{duration:.3f}s"
return responseEl ciclo completo: peticion HTTP → WSGI/ASGI → middlewares (process_request) → resolutor de URLs → vista → middlewares (process_response) → respuesta HTTP.
ORM y Base de Datos
Pregunta 4: Como funciona el QuerySet de Django y que es la carga diferida?
Los QuerySets se evaluan de forma diferida: ninguna consulta SQL se ejecuta hasta que los datos se utilizan realmente.
# queryset_lazy.py
# Demonstrating QuerySet lazy loading
# No SQL query executed here
qs = Article.objects.filter(published=True) # No query
qs = qs.exclude(title="Draft") # Still none
qs = qs.order_by("-created_at") # Still none
# The SQL query runs ONLY here
for article in qs: # ONE combined SQL query
print(article.title)
# Other evaluation triggers
list(qs) # Converting to list
qs[0] # Index access
len(qs) # Counting (prefer qs.count())
bool(qs) # Existence check (prefer qs.exists())Esta evaluacion diferida permite encadenar filtros sin sobrecarga, ejecutando una sola consulta optimizada.
Pregunta 5: Que es el problema N+1 y como resolverlo?
El problema N+1 ocurre cuando una consulta principal genera N consultas adicionales para cargar relaciones. Es la causa mas comun de lentitud en aplicaciones Django.
# n_plus_one.py
# N+1 problem and solutions
# ❌ PROBLEM: N+1 queries
# 1 query for articles + 1 query PER article for the author
articles = Article.objects.all()
for article in articles:
print(article.author.username) # SQL query on every iteration!
# ✅ SOLUTION 1: select_related (ForeignKey, OneToOne)
# Joins tables in ONE SQL query (JOIN)
articles = Article.objects.select_related("author").all()
for article in articles:
print(article.author.username) # No additional query
# ✅ SOLUTION 2: prefetch_related (ManyToMany, reverse FK)
# Executes 2 separate queries + Python assembly
articles = Article.objects.prefetch_related("tags").all()
for article in articles:
print(article.tags.all()) # Data already cached
# ✅ SOLUTION 3: Custom Prefetch with filtering
from django.db.models import Prefetch
articles = Article.objects.prefetch_related(
Prefetch(
"comments",
queryset=Comment.objects.filter(approved=True).select_related("user"),
to_attr="approved_comments" # Custom attribute
)
)Se utiliza select_related para relaciones ForeignKey/OneToOne (SQL JOIN) y prefetch_related para relaciones ManyToMany o inversas (consultas separadas).
Pregunta 6: Como crear un Manager personalizado y cuando usarlo?
Los Managers personalizados encapsulan consultas frecuentes a nivel del modelo, haciendo el codigo mas legible y reutilizable.
# managers.py
# Custom Managers and QuerySets
class PublishedQuerySet(models.QuerySet):
"""Reusable QuerySet for published articles."""
def published(self):
return self.filter(status="published", published_at__lte=timezone.now())
def by_author(self, user):
return self.filter(author=user)
def popular(self):
return self.annotate(
comment_count=models.Count("comments")
).order_by("-comment_count")
class PublishedManager(models.Manager):
"""Manager that exposes only published articles."""
def get_queryset(self):
return PublishedQuerySet(self.model, using=self._db).published()
class Article(models.Model):
# ...
objects = models.Manager() # Default manager (all articles)
published = PublishedManager() # Custom manager (published only)
# Usage:
# Article.objects.all() → All articles
# Article.published.all() → Published articles only
# Article.published.popular() → Published articles sorted by popularityLos Managers personalizados siguen el principio DRY y centralizan la logica de consultas.
¿Listo para aprobar tus entrevistas de Django?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Vistas y URLs
Pregunta 7: Cuando usar Class-Based Views vs Function-Based Views?
Las Function-Based Views (FBVs) ofrecen simplicidad y control explicito. Las Class-Based Views (CBVs) aportan reutilizacion y estructura mediante herencia.
# views_comparison.py
# FBV: Explicit, simple, easy to understand
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def article_list(request):
if request.method == "GET":
articles = Article.published.all()
return render(request, "articles/list.html", {"articles": articles})
# POST: article creation
form = ArticleForm(request.POST)
if form.is_valid():
form.save()
return redirect("article-list")
return render(request, "articles/list.html", {"form": form})# views_cbv.py
# CBV: Reusable, extensible via mixins
from django.views.generic import ListView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = "articles/list.html"
context_object_name = "articles" # Variable name in the template
paginate_by = 20 # Automatic pagination
def get_queryset(self):
# Override to filter published articles
return Article.published.all()
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
form_class = ArticleForm
success_url = reverse_lazy("article-list")
def form_valid(self, form):
form.instance.author = self.request.user # Assign the author
return super().form_valid(form)Regla practica: usar FBVs para logica simple o no estandar, CBVs para operaciones CRUD estandar.
Pregunta 8: Como funcionan los middlewares en Django?
Los middlewares son hooks que procesan cada peticion/respuesta. Cada middleware puede intervenir en diferentes fases del ciclo de procesamiento.
# auth_middleware.py
# Custom authentication middleware
import jwt
from django.conf import settings
from django.http import JsonResponse
class JWTAuthenticationMiddleware:
"""Verifies JWT token on protected endpoints."""
EXEMPT_PATHS = ["/api/auth/login", "/api/auth/register", "/health"]
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Skip exempt paths
if any(request.path.startswith(p) for p in self.EXEMPT_PATHS):
return self.get_response(request)
# Extract and verify the token
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
return JsonResponse({"error": "Missing token"}, status=401)
try:
token = auth_header.split(" ")[1]
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
request.user_id = payload["user_id"] # Attach to request
except jwt.ExpiredSignatureError:
return JsonResponse({"error": "Token expired"}, status=401)
except jwt.InvalidTokenError:
return JsonResponse({"error": "Invalid token"}, status=401)
return self.get_response(request)El orden de los middlewares en MIDDLEWARE es crucial: se ejecutan de arriba hacia abajo para las peticiones y de abajo hacia arriba para las respuestas.
Django REST Framework
Pregunta 9: Cual es la diferencia entre Serializer y ModelSerializer?
Serializer define manualmente cada campo, mientras que ModelSerializer genera automaticamente los campos a partir del modelo.
# serializers.py
from rest_framework import serializers
# Manual Serializer: full control over each field
class ArticleSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=200)
content = serializers.CharField()
author_name = serializers.SerializerMethodField()
def get_author_name(self, obj):
return obj.author.get_full_name()
def create(self, validated_data):
return Article.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.title = validated_data.get("title", instance.title)
instance.content = validated_data.get("content", instance.content)
instance.save()
return instance
# ModelSerializer: automatic field generation
class ArticleModelSerializer(serializers.ModelSerializer):
author_name = serializers.SerializerMethodField()
comment_count = serializers.IntegerField(read_only=True)
class Meta:
model = Article
fields = ["id", "title", "content", "author", "author_name",
"comment_count", "published_at"]
read_only_fields = ["published_at"]
def get_author_name(self, obj):
return obj.author.get_full_name()Se recomienda ModelSerializer para casos estandar y Serializer cuando la representacion difiere significativamente del modelo.
Pregunta 10: Como implementar paginacion en DRF?
DRF ofrece varias estrategias de paginacion configurables globalmente o por vista.
# settings.py
# Global pagination configuration
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}
# pagination.py
# Custom pagination per view
from rest_framework.pagination import CursorPagination, LimitOffsetPagination
class ArticleCursorPagination(CursorPagination):
"""Cursor pagination: performant for large datasets."""
page_size = 20
ordering = "-published_at" # Indexed field required
cursor_query_param = "cursor"
class ArticleLimitOffsetPagination(LimitOffsetPagination):
"""Offset/limit pagination: flexible but less performant."""
default_limit = 20
max_limit = 100
# views.py
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.published.all()
serializer_class = ArticleModelSerializer
pagination_class = ArticleCursorPagination # View-specific paginationLa paginacion por cursor es recomendada para conjuntos de datos grandes ya que mantiene el rendimiento sin importar el numero de pagina, a diferencia de OFFSET/LIMIT.
Pregunta 11: Como asegurar una API con permisos de DRF?
DRF proporciona un sistema modular de permisos que combina autenticacion y autorizacion granular.
# permissions.py
from rest_framework.permissions import BasePermission, IsAuthenticated
class IsAuthorOrReadOnly(BasePermission):
"""Only the author can modify, everyone can read."""
def has_object_permission(self, request, view, obj):
# GET, HEAD, OPTIONS are always allowed
if request.method in ("GET", "HEAD", "OPTIONS"):
return True
# Only the author can modify or delete
return obj.author == request.user
class IsAdminOrManager(BasePermission):
"""Access restricted to admins and managers."""
def has_permission(self, request, view):
return (
request.user.is_authenticated
and request.user.role in ("admin", "manager")
)
# views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.throttling import UserRateThrottle
class ArticleViewSet(ModelViewSet):
permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
throttle_classes = [UserRateThrottle] # Rate limiting
def get_permissions(self):
# Dynamic permissions based on action
if self.action == "destroy":
return [IsAdminOrManager()]
return super().get_permissions()Se combinan permission_classes a nivel de vista y has_object_permission para control granular por objeto.
Signals y Tareas Asincronas
Pregunta 12: Como funcionan los signals de Django y cuando usarlos?
Los signals permiten desacoplar componentes reaccionando a eventos del framework o de la aplicacion.
# signals.py
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django.core.mail import send_mail
@receiver(post_save, sender=Article)
def notify_on_publish(sender, instance, created, **kwargs):
"""Sends a notification when an article is published."""
if not created and instance.status == "published":
# Triggered only on publication (not creation)
subscribers = instance.author.subscribers.values_list("email", flat=True)
send_mail(
subject=f"New article: {instance.title}",
message=f"Check out the latest article by {instance.author.username}",
from_email="noreply@example.com",
recipient_list=list(subscribers),
)
@receiver(pre_delete, sender=Article)
def cleanup_article_files(sender, instance, **kwargs):
"""Deletes associated files before article deletion."""
if instance.cover_image:
instance.cover_image.delete(save=False) # Deletes the physical fileLos signals son adecuados para efectos secundarios ligeros (logging, invalidacion de cache). Para tareas pesadas, se recomienda Celery.
Pregunta 13: Como integrar Celery con Django para tareas asincronas?
Celery permite la ejecucion de tareas en segundo plano, esencial para operaciones de larga duracion como envio de correos o procesamiento de archivos.
# celery_config.py
# Celery configuration in the Django project
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
app = Celery("myproject")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks() # Discovers tasks.py in each app
# tasks.py
from celery import shared_task
from django.core.mail import send_mass_mail
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_newsletter(self, article_id):
"""Sends newsletter asynchronously."""
try:
article = Article.objects.get(id=article_id)
subscribers = User.objects.filter(newsletter=True)
messages = [
(f"New: {article.title}", article.content[:200],
"noreply@example.com", [sub.email])
for sub in subscribers
]
send_mass_mail(messages, fail_silently=False)
except Article.DoesNotExist:
pass # Article was deleted in the meantime
except Exception as exc:
self.retry(exc=exc) # Automatic retry on error
# Calling from a view
# send_newsletter.delay(article.id) # Async execution
# send_newsletter.apply_async(args=[article.id], countdown=300) # 5-min delayCelery es esencial en produccion para cualquier operacion que no deba bloquear la respuesta HTTP.
Seguridad y Autenticacion
Pregunta 14: Como protege Django contra ataques CSRF?
Django incluye proteccion CSRF integrada mediante un middleware que verifica un token unico en cada peticion POST.
# CSRF protection in forms
# The {% csrf_token %} template tag generates a hidden field
# For APIs (DRF), CSRF is often disabled in favor of tokens
# settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication", # Includes CSRF
"rest_framework.authentication.TokenAuthentication", # No CSRF
],
}
# For AJAX views with session auth
# The csrftoken cookie must be sent in the X-CSRFToken header# csrf_exemption.py
# Exempting a specific view (use with caution)
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
@ensure_csrf_cookie
def get_csrf_token(request):
"""Endpoint that forces sending the CSRF cookie to the client."""
return JsonResponse({"detail": "CSRF cookie set"})
@csrf_exempt # ⚠️ Use only for external webhooks
def stripe_webhook(request):
"""Stripe webhook - authenticated by signature, not CSRF."""
payload = request.body
sig_header = request.headers.get("Stripe-Signature")
# Verified by Stripe signature insteadNunca se debe deshabilitar CSRF globalmente. Se utiliza csrf_exempt unicamente en endpoints autenticados por otros medios (webhooks, tokens de API).
Pregunta 15: Como implementar autenticacion personalizada en Django?
Django permite reemplazar el modelo de User predeterminado y personalizar el backend de autenticacion.
# models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class CustomUserManager(BaseUserManager):
"""Manager for the custom User model."""
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("Email is required")
email = self.normalize_email(email) # Normalizes the domain
user = self.model(email=email, **extra_fields)
user.set_password(password) # Hashes the password
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True) # Login by email
username = models.CharField(max_length=30, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
objects = CustomUserManager()
USERNAME_FIELD = "email" # Field used for login
REQUIRED_FIELDS = [] # Fields required in addition to USERNAME_FIELD
# settings.py
AUTH_USER_MODEL = "users.CustomUser" # Before the first migration!Es necesario definir AUTH_USER_MODEL al inicio del proyecto. Cambiarlo despues de las migraciones iniciales es complejo y riesgoso.
Optimizacion y Rendimiento
Pregunta 16: Como optimizar las consultas del ORM de Django?
La optimizacion de consultas es critica para el rendimiento. Varias tecnicas reducen el numero y costo de las consultas SQL.
# query_optimization.py
from django.db.models import F, Q, Count, Avg, Prefetch
# 1. Only/Defer: load only needed fields
articles = Article.objects.only("title", "published_at") # SELECT title, published_at
heavy_articles = Article.objects.defer("content") # Everything EXCEPT content
# 2. SQL-level aggregations (not Python)
stats = Article.objects.aggregate(
total=Count("id"),
avg_views=Avg("view_count"),
)
# 3. F() expressions: SQL-level operations
Article.objects.filter(published=True).update(
view_count=F("view_count") + 1 # Atomic SQL increment
)
# 4. Q() objects: complex queries
results = Article.objects.filter(
Q(title__icontains="django") | Q(tags__name="python"),
~Q(status="draft"), # NOT draft
published_at__year=2026
)
# 5. Bulk operations: reduce INSERT/UPDATE queries
articles = [Article(title=f"Article {i}") for i in range(100)]
Article.objects.bulk_create(articles, batch_size=50) # 2 queries instead of 100
Article.objects.filter(status="draft").update(status="archived") # 1 querySe recomienda usar django-debug-toolbar en desarrollo para identificar consultas lentas y problemas N+1.
Pregunta 17: Como implementar cache en Django?
Django proporciona un framework de cache multinivel: por vista, por fragmento de template o para datos arbitrarios.
# settings.py
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
}
}
# cache_strategies.py
from django.core.cache import cache
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
# Per-view cache: caches the entire HTTP response
@cache_page(60 * 15) # 15 minutes
def article_list(request):
return render(request, "articles/list.html", {"articles": Article.published.all()})
# Data cache: granular control
def get_popular_articles():
cache_key = "popular_articles_v1"
articles = cache.get(cache_key)
if articles is None:
articles = list(
Article.published.popular()[:10].values("id", "title", "view_count")
)
cache.set(cache_key, articles, timeout=60 * 30) # 30 min
return articles
# Cache invalidation
def invalidate_article_cache(article_id):
cache.delete(f"article_{article_id}")
cache.delete("popular_articles_v1")
cache.delete_pattern("article_list_*") # With django-redisSe recomienda Redis como backend de cache en produccion por su persistencia y funcionalidades avanzadas (patrones, TTL).
¿Listo para aprobar tus entrevistas de Django?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
Migraciones y Gestion de Base de Datos
Pregunta 18: Como manejar migraciones complejas en Django?
Las migraciones de Django gestionan la evolucion del esquema de base de datos de forma versionada y reproducible.
# 0005_migrate_data.py
# Custom data migration
from django.db import migrations
def migrate_user_roles(apps, schema_editor):
"""Converts is_admin booleans to text roles."""
User = apps.get_model("users", "CustomUser")
# Use apps.get_model() to access the historical model
User.objects.filter(is_admin=True).update(role="admin")
User.objects.filter(is_admin=False, is_staff=True).update(role="manager")
User.objects.filter(is_admin=False, is_staff=False).update(role="user")
def reverse_migrate(apps, schema_editor):
"""Reverse migration for rollback."""
User = apps.get_model("users", "CustomUser")
User.objects.filter(role="admin").update(is_admin=True)
class Migration(migrations.Migration):
dependencies = [
("users", "0004_add_role_field"),
]
operations = [
migrations.RunPython(migrate_user_roles, reverse_migrate),
]Siempre se debe proporcionar una funcion reverse para permitir el rollback. Las migraciones deben probarse en una copia de la base de datos de produccion antes del despliegue.
Pregunta 19: Como crear indices personalizados para optimizacion?
Los indices aceleran las consultas frecuentes pero incrementan el costo de escritura. La seleccion cuidadosa es esencial.
# models.py
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
status = models.CharField(max_length=20, db_index=True) # Simple index
published_at = models.DateTimeField(null=True)
author = models.ForeignKey("auth.User", on_delete=models.CASCADE)
class Meta:
indexes = [
# Composite index for frequent queries
models.Index(fields=["status", "-published_at"], name="idx_status_date"),
# Partial index: only published articles
models.Index(
fields=["published_at"],
condition=models.Q(status="published"),
name="idx_published_articles"
),
# GIN index for full-text search (PostgreSQL)
GinIndex(fields=["search_vector"], name="idx_search"),
]Los indices compuestos siguen el orden de columnas: el campo mas selectivo debe ir primero.
Testing y Calidad
Pregunta 20: Como estructurar los tests en un proyecto Django?
Django proporciona un framework de testing robusto basado en unittest, mejorado por pytest-django para mayor flexibilidad.
# tests/test_views.py
from django.test import TestCase, Client
from django.urls import reverse
from rest_framework.test import APITestCase, APIClient
class ArticleViewTests(TestCase):
"""View tests with Django's test client."""
def setUp(self):
self.client = Client()
self.user = CustomUser.objects.create_user(
email="test@example.com", password="testpass123"
)
self.article = Article.objects.create(
title="Test Article",
content="Content here",
author=self.user,
status="published"
)
def test_article_list_returns_200(self):
response = self.client.get(reverse("article-list"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Test Article")
def test_create_article_requires_auth(self):
response = self.client.post(reverse("article-create"), {"title": "New"})
self.assertEqual(response.status_code, 302) # Redirects to login
class ArticleAPITests(APITestCase):
"""REST API tests with DRF."""
def setUp(self):
self.user = CustomUser.objects.create_user(
email="api@example.com", password="testpass123"
)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def test_create_article_via_api(self):
data = {"title": "API Article", "content": "Created via API"}
response = self.client.post("/api/articles/", data, format="json")
self.assertEqual(response.status_code, 201)
self.assertEqual(Article.objects.count(), 1)Los tests deben separarse en archivos por dominio: test_models.py, test_views.py, test_serializers.py, test_services.py.
Pregunta 21: Como usar fixtures y factories para tests?
Las factories (con factory_boy) son preferibles a los fixtures JSON por su flexibilidad y mantenibilidad de datos de prueba.
# factories.py
import factory
from factory.django import DjangoModelFactory
class UserFactory(DjangoModelFactory):
class Meta:
model = CustomUser
email = factory.Sequence(lambda n: f"user{n}@example.com")
username = factory.Faker("user_name")
is_active = True
class ArticleFactory(DjangoModelFactory):
class Meta:
model = Article
title = factory.Faker("sentence", nb_words=5)
content = factory.Faker("paragraphs", nb=3)
author = factory.SubFactory(UserFactory) # Creates a user automatically
status = "published"
class Params:
draft = factory.Trait(status="draft", published_at=None)
# tests.py
def test_published_articles_count(self):
ArticleFactory.create_batch(5) # 5 published articles
ArticleFactory.create_batch(3, draft=True) # 3 drafts
self.assertEqual(Article.published.count(), 5)Las factories aseguran datos de prueba consistentes y evitan dependencias entre tests.
Patrones Avanzados
Pregunta 22: Como implementar WebSockets con Django Channels?
Django Channels extiende Django mas alla de HTTP para soportar WebSockets, protocolos en tiempo real y tareas en segundo plano.
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
"""WebSocket consumer for real-time chat."""
async def connect(self):
self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
self.room_group = f"chat_{self.room_name}"
# Join the room group
await self.channel_layer.group_add(self.room_group, self.channel_name)
await self.accept()
async def disconnect(self, close_code):
# Leave the group
await self.channel_layer.group_discard(self.room_group, self.channel_name)
async def receive(self, text_data):
data = json.loads(text_data)
# Broadcast message to the entire group
await self.channel_layer.group_send(
self.room_group,
{"type": "chat.message", "message": data["message"],
"username": self.scope["user"].username}
)
async def chat_message(self, event):
# Send message to the WebSocket client
await self.send(text_data=json.dumps({
"message": event["message"],
"username": event["username"],
}))Django Channels utiliza ASGI (en lugar de WSGI) y requiere un servidor compatible como Daphne o Uvicorn.
Pregunta 23: Explicar el patron Repository y Service Layer en Django
El patron Service Layer separa la logica de negocio de las vistas y el ORM, facilitando las pruebas y el mantenimiento.
# services/article_service.py
from django.db import transaction
class ArticleService:
"""Service encapsulating article business logic."""
@staticmethod
def publish_article(article_id: int, user) -> Article:
"""Publishes an article with all validations."""
article = Article.objects.select_for_update().get(id=article_id)
if article.author != user:
raise PermissionError("Only the author can publish this article")
if article.status == "published":
raise ValueError("Article is already published")
article.status = "published"
article.published_at = timezone.now()
article.save(update_fields=["status", "published_at"])
# Side effects: notification, cache, analytics
send_newsletter.delay(article.id)
cache.delete("popular_articles_v1")
return article
@staticmethod
@transaction.atomic
def bulk_archive(article_ids: list[int], user) -> int:
"""Archives multiple articles in a transaction."""
updated = Article.objects.filter(
id__in=article_ids,
author=user,
status="published"
).update(status="archived", archived_at=timezone.now())
return updatedEl Service Layer es el punto de entrada para toda la logica de negocio. Las vistas y serializers delegan al servicio, nunca directamente al ORM.
Pregunta 24: Como gestionar variables de entorno y configuracion multi-ambiente?
La gestion de configuracion sigue los principios de 12-Factor App: separacion estricta entre configuracion y codigo.
# settings/base.py
# Shared configuration across all environments
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv() # Loads the .env file
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] # Required, no default value
DEBUG = os.environ.get("DEBUG", "False").lower() == "true"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ.get("DB_NAME", "myapp"),
"USER": os.environ.get("DB_USER", "postgres"),
"HOST": os.environ.get("DB_HOST", "localhost"),
"PORT": os.environ.get("DB_PORT", "5432"),
}
}
# settings/production.py
from .base import *
DEBUG = False
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000 # 1 yearNunca se deben incluir secretos en el codigo. Se utilizan variables de entorno o un gestor de secretos (Vault, AWS Secrets Manager).
Pregunta 25: Como desplegar una aplicacion Django en produccion?
El despliegue en produccion requiere una lista de verificacion completa que abarca seguridad, rendimiento y confiabilidad.
# Django deployment checklist
# 1. Built-in verification command
# python manage.py check --deploy
# 2. WSGI/ASGI configuration for production
# gunicorn.conf.py
import multiprocessing
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1 # Recommended formula
worker_class = "gthread" # Threaded workers
threads = 4
max_requests = 1000 # Recycle workers to avoid memory leaks
max_requests_jitter = 50
timeout = 30
accesslog = "-" # Logs to stdout
errorlog = "-"# docker-compose.yml (typical configuration)
# Services: web (gunicorn), db (postgres), redis (cache/celery), worker (celery)
# 3. Static files
# python manage.py collectstatic --noinput
# Serve via nginx or CDN (WhiteNoise for simple cases)
# 4. Nginx configuration
# - Proxy to gunicorn on port 8000
# - Serve /static/ and /media/ directly
# - Enable gzip, HTTP/2, and security headersSe debe ejecutar python manage.py check --deploy antes de cada release a produccion. Este comando verifica configuraciones de seguridad esenciales.
Conclusion
Estas 25 preguntas cubren los aspectos esenciales de las entrevistas de Django y Python, desde los fundamentos de la arquitectura MVT hasta los patrones de despliegue en produccion.
Lista de preparacion:
- ✅ Arquitectura MVT y ciclo de vida de peticiones
- ✅ ORM: QuerySets, N+1, select_related, prefetch_related
- ✅ Django REST Framework: serializers, paginacion, permisos
- ✅ Seguridad: CSRF, autenticacion, permisos
- ✅ Rendimiento: optimizacion del ORM, cache, indices
- ✅ Testing: TestCase, APITestCase, factories
- ✅ Patrones avanzados: Channels, Service Layer, despliegue
Cada pregunta merece una exploracion mas detallada con la documentacion oficial de Django. Los entrevistadores valoran a los candidatos que comprenden las sutilezas del framework y pueden justificar sus decisiones tecnicas.
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
Etiquetas
Compartir
Artículos relacionados

Django 5: Crear una API REST con Django REST Framework
Guia completa para construir una API REST profesional con Django 5 y DRF. Serializers, ViewSets, autenticacion JWT y buenas practicas explicadas paso a paso.

Preguntas de entrevista Django: ORM, Middleware y DRF a fondo
Preguntas de entrevista Django sobre optimización del ORM con select_related y prefetch_related, arquitectura de middleware y rendimiento de serializers en Django REST Framework, permisos y paginación.

Las 25 preguntas principales en entrevistas de Data Analytics en 2026
Las 25 preguntas más frecuentes en entrevistas de data analytics en 2026: SQL, Python, Power BI, estadística y preguntas conductuales con respuestas detalladas y ejemplos de código.