Convertir django RawQuerySet a Queryset

Tengo 2 modelos Django, ModelA con un ArrayField que se utiliza para almacenar una gran lista de valores de clave principal (posiblemente 50k + lista)

 class ModelA(models.Model): pk_values = ArrayField(models.IntegerField()) class CustomManager(manager.Manager): def get_for_index(self, index_id): qs = self.get_queryset() obj = ModelA.objects.get(pk=index_id) return qs.filter(id__in=obj.pk_values) class ModelB(models.Model): # [...] some fields objects = CustomManager() 

Esto funciona:

 qs = ModelB.objects.get_for_index(index_id=1) 

Sin embargo, esto sería súper lento donde “pk_values” es una lista grande.

Así que traté de hacer consultas SQL en bruto:

 class CustomManager(manager.Manager): def get_for_index(self, index_id): qs = self.get_queryset() sql = "SELECT * FROM myapp_model_b JOIN myapp_model_a ON myapp_model_b.id = ANY(myapp_model_a.pk_values) WHERE myapp_model_a.id = '%s'" % index_id return qs.raw(sql) 

Pero esto devuelve una instancia django.db.models.query.RawQuerySet .

Pero con esto, no puedo hacer cosas como queryset.values() después.

¿Cómo puedo convertir esto a un queryset Django normal?

¿Hay una mejor manera de hacer esto?

Docs:

  • ArrayField https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#arrayfield
  • Administrador personalizado https://docs.djangoproject.com/en/2.0/topics/db/managers/#custom-managers-and-model-inheritance
  • Consultas sin procesar https://docs.djangoproject.com/en/2.0/topics/db/sql/#performing-raw-sql-queries

Puedes usar una expresión RawSQL :

 ModelB.objects.filter(id__in=RawSQL( 'SELECT unnest(a.pk_values) FROM app_modela a WHERE a.id = %s', [index_id] )) 

Alternativamente, puede reproducir la consulta exacta que tiene en su pregunta con extra () :

 ModelB.objects.extra( tables=['foo_modela'], where=[ '"app_modelb"."id" = ANY("app_modela"."pk_values")', '"app_modela"."id" = %s', ], params=[index_id], ) 

Actualización: Tengo algo funcionando usando .extra()

 class CustomManager(manager.Manager): def get_for_index(self, index_id): qs = self.get_queryset() sql = "myapp_model_b.id IN (SELECT UNNEST(myapp_model_a.pk_values) FROM myapp_model_a WHERE myapp_model_a.id='%s')" % index_id return qs.extra(where=[sql]) 

Docs: https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.extra