TalentFlow SaaS · Django 4.2 + DRF 3.14 + PostgreSQL 15 · Generado por CULTIVA IA · 16 jun 2026
# serializers.py — 3 queries por cada Application en el listado class ApplicationSerializer(serializers.ModelSerializer): def get_candidate_name(self, obj): return obj.candidate.full_name # ← query N+1 def get_candidate_email(self, obj): return obj.candidate.email # ← query N+1 (mismo rel.) def get_application_count(self, obj): return obj.candidate.applications.count() # ← query N+1
def get_queryset(self): job_id = self.kwargs.get('job_pk') return Application.objects .filter(job_id=job_id) .order_by('-created')
def get_queryset(self): job_id = self.kwargs.get('job_pk') return Application.objects .filter(job_id=job_id) .select_related('candidate') .annotate( app_count=Count('candidate__applications') ) .order_by('-created')
class ApplicationSerializer(serializers.ModelSerializer): candidate_name = serializers.CharField(source='candidate.full_name', read_only=True) candidate_email = serializers.EmailField(source='candidate.email', read_only=True) application_count = serializers.IntegerField(read_only=True) # viene de la anotación
# serializers.py — 4 queries por cada Job def get_company_name(self, obj): return obj.company.name # ← N+1 def get_application_count(self, obj): return obj.applications.count() # ← N+1 def get_latest_applicant(self, obj): app = obj.applications.order_by('-created').first() # ← N+1 if app: return app.candidate.full_name # ← N+1 adicional
# views.py — un único queryset optimizado def get_queryset(self): from django.db.models import Count, Subquery, OuterRef latest_app_qs = (Application.objects .filter(job=OuterRef('pk')) .select_related('candidate') .order_by('-created') .values('candidate__full_name')[:1] ) return (Job.objects .filter(company=self.request.user.company) .select_related('company') .annotate( application_count=Count('applications'), latest_applicant=Subquery(latest_app_qs), ) .order_by('-published_at') )
# views.py from rest_framework.pagination import PageNumberPagination class JobPagination(PageNumberPagination): page_size = 25 page_size_query_param = 'page_size' max_page_size = 100 class JobViewSet(viewsets.ModelViewSet): serializer_class = JobSerializer pagination_class = JobPagination # ← añadir ...
class ApplicationPagination(PageNumberPagination): page_size = 50 max_page_size = 200 class ApplicationViewSet(viewsets.ModelViewSet): pagination_class = ApplicationPagination # ← añadir ...
class Job(models.Model): status = models.CharField(max_length=20, default='draft', db_index=True) # ← añadir published_at = models.DateTimeField(null=True, blank=True, db_index=True) # ← añadir class Meta: indexes = [ models.Index(fields=['company', 'status']), # patrón filter más frecuente models.Index(fields=['status', '-published_at']), # orden frecuente ] class Candidate(models.Model): email = models.EmailField(db_index=True) # ← añadir; deduplicación en import
class Application(models.Model): class Meta: indexes = [ models.Index(fields=['job', 'stage']), # bulk_reject filter models.Index(fields=['job', '-created']), # listado ordenado models.Index(fields=['candidate', '-created']), # perfil del candidato ]
def bulk_reject(self, ...): apps = Application.objects.filter( job_id=job_pk, stage='applied' ) for app in apps: app.stage = 'rejected' app.save() # ← N UPDATEs
def bulk_reject(self, ...): updated = Application.objects.filter( job_id=job_pk, stage='applied' ).update(stage='rejected') # 1 sola query UPDATE return Response({'updated': updated})
for row in data: c = Candidate.objects.create( email=row['email'], full_name=row['full_name'], ) Application.objects.create( job_id=job_pk, candidate=c, ) # ← 2N inserts
candidates = Candidate.objects.bulk_create(
[Candidate(email=r['email'],
full_name=r['full_name'])
for r in data],
ignore_conflicts=True,
)
Application.objects.bulk_create(
[Application(job_id=job_pk, candidate=c)
for c in candidates],
batch_size=500,
) # ← 2 inserts batch
# Documentar explícitamente el requisito de select_related class Application(models.Model): @property def candidate_email(self): """Accede a candidate FK. Requiere select_related('candidate') en el queryset.""" return self.candidate.email