Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

308
Vistas
Django ORM: ¿Equivalente de SQL `NO EN`? Los objetos `exclude` y `Q` no funcionan

El problema

Estoy tratando de usar Django ORM para hacer el equivalente de una cláusula SQL NOT IN , proporcionando una lista de ID en una subselección para recuperar un conjunto de registros de la tabla de registro. No puedo averiguar si esto es posible.

El modelo

 class JobLog(models.Model): job_number = models.BigIntegerField(blank=True, null=True) name = models.TextField(blank=True, null=True) username = models.TextField(blank=True, null=True) event = models.TextField(blank=True, null=True) time = models.DateTimeField(blank=True, null=True)

lo que he probado

Mi primer intento fue usar exclude , pero esto NOT niega toda la Subquery , en lugar del deseado NOT IN :

 query = ( JobLog.objects.values( "username", "job_number", "name", "time", ) .filter(time__gte=start, time__lte=end, event="delivered") .exclude( job_number__in=models.Subquery( JobLog.objects.values_list("job_number", flat=True).filter( time__gte=start, time__lte=end, event="finished", ) ) ) )

Desafortunadamente, esto produce este SQL:

 SELECT "view_job_log"."username", "view_job_log"."group", "view_job_log"."job_number", "view_job_log"."name", "view_job_log"."time" FROM "view_job_log" WHERE ( "view_job_log"."event" = 'delivered' AND "view_job_log"."time" >= '2020-03-12T11:22:28.300590+00:00'::timestamptz AND "view_job_log"."time" <= '2020-03-13T11:22:28.300600+00:00'::timestamptz AND NOT ( "view_job_log"."job_number" IN ( SELECT U0."job_number" FROM "view_job_log" U0 WHERE ( U0."event" = 'finished' AND U0."time" >= '2020-03-12T11:22:28.300590+00:00'::timestamptz AND U0."time" <= '2020-03-13T11:22:28.300600+00:00'::timestamptz ) ) AND "view_job_log"."job_number" IS NOT NULL ) )

Lo que necesito es que la tercera cláusula AND sea AND "view_job_log"."job_number" NOT IN en lugar de AND NOT ( .

También intenté hacer la subselección como su propia consulta primero, con una exclude , como se sugiere aquí:

Django equivalente de SQL no en

Sin embargo, esto produce el mismo resultado problemático. Luego probé un objeto Q , que produce una consulta similar:

 query = ( JobLog.objects.values( "username", "subscriber_code", "job_number", "name", "time", ) .filter( ~models.Q(job_number__in=models.Subquery( JobLog.objects.values_list("job_number", flat=True).filter( time__gte=start, time__lte=end, event="finished", ) )), time__gte=start, time__lte=end, event="delivered", ) )

Este intento con el objeto Q produce el siguiente SQL, nuevamente, sin NOT IN :

 SELECT "view_job_log"."username", "view_job_log"."group", "view_job_log"."job_number", "view_job_log"."name", "view_job_log"."time" FROM "view_job_log" WHERE ( NOT ( "view_job_log"."job_number" IN ( SELECT U0."job_number" FROM "view_job_log" U0 WHERE ( U0."event" = 'finished' AND U0."time" >= '2020-03-12T11:33:28.098653+00:00'::timestamptz AND U0."time" <= '2020-03-13T11:33:28.098678+00:00'::timestamptz ) ) AND "view_job_log"."job_number" IS NOT NULL ) AND "view_job_log"."event" = 'delivered' AND "view_job_log"."time" >= '2020-03-12T11:33:28.098653+00:00'::timestamptz AND "view_job_log"."time" <= '2020-03-13T11:33:28.098678+00:00'::timestamptz )

¿Hay alguna forma de hacer que el ORM de Django haga algo equivalente a AND job_number NOT IN (12345, 12346, 12347) ? ¿O tendré que pasar a SQL sin procesar para lograr esto?

Gracias de antemano por leer toda esta pregunta del muro de texto. Explícito es mejor que implícito. :)

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Puedes probar esto:

 JobLog.objects.filter(time__gte=start, time__lte=end, event="delivered").exclude(time__gte=start, event='finished').exclude(time__lte=end, event='finished')
over 4 years ago · Santiago Trujillo Denunciar

0

Creo que la forma más fácil de hacer esto sería definir una búsqueda personalizada, similar a esta o la búsqueda en

 from django.db.models.lookups import In as LookupIn class NotIn(LookupIn): lookup_name = "notin" def get_rhs_op(self, connection, rhs): return "NOT IN %s" % rhs Field.register_lookup(NotIn)

o

 class NotIn(models.Lookup): lookup_name = "notin" def as_sql(self, compiler, connection): lhs, params = self.process_lhs(compiler, connection) rhs, rhs_params = self.process_rhs(compiler, connection) params.extend(rhs_params) return "%s NOT IN %s" % (lhs, rhs), params

luego úsalo en tu consulta:

 query = ( JobLog.objects.values( "username", "job_number", "name", "time", ) .filter(time__gte=start, time__lte=end, event="delivered") .filter( job_number__notin=models.Subquery( JobLog.objects.values_list("job_number", flat=True).filter( time__gte=start, time__lte=end, event="finished", ) ) ) )

esto genera el SQL:

 SELECT "people_joblog"."username", "people_joblog"."job_number", "people_joblog"."name", "people_joblog"."time" FROM "people_joblog" WHERE ("people_joblog"."event" = delivered AND "people_joblog"."time" >= 2020 - 03 - 13 15:24:34.691222 + 00:00 AND "people_joblog"."time" <= 2020 - 03 - 13 15:24:41.678069 + 00:00 AND "people_joblog"."job_number" NOT IN ( SELECT U0. "job_number" FROM "people_joblog" U0 WHERE (U0. "event" = finished AND U0. "time" >= 2020 - 03 - 13 15:24:34.691222 + 00:00 AND U0. "time" <= 2020 - 03 - 13 15:24:41.678069 + 00:00)))
over 4 years ago · Santiago Trujillo Denunciar

0

Es probable que pueda lograr los mismos resultados utilizando Exists y NULL s de mayúsculas y minúsculas especiales.

 .filter( ~Exists( JobLog.objects.filter( Q(jobnumber=None) | Q(jobnumber=OuterRef('jobnumber')), time__gte=start, time__lte=end, event='finished', ) ) )
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda