将 Django RawQuerySet 转换为查询集
Convert django RawQuerySet to Queryset
我有 2 个 Django 模型,ModelA
带有一个 ArrayField
用于存储大量主键值列表(可能超过 50k 个列表)
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()
这个有效:
qs = ModelB.objects.get_for_index(index_id=1)
但是,如果 "pk_values" 是一个大列表,这会非常慢。
所以我尝试进行原始 SQL 查询:
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)
但是这个 returns 一个 django.db.models.query.RawQuerySet
实例。
但是有了这个,我以后就不能做像queryset.values()
这样的事情了。
如何将其转换为普通的 Django 查询集?
有更好的方法吗?
文档:
您可以使用 RawSQL 表达式:
ModelB.objects.filter(id__in=RawSQL(
'SELECT unnest(a.pk_values) FROM app_modela a WHERE a.id = %s',
[index_id]
))
或者,您可以使用 extra():
重现问题中的确切查询
ModelB.objects.extra(
tables=['foo_modela'],
where=[
'"app_modelb"."id" = ANY("app_modela"."pk_values")',
'"app_modela"."id" = %s',
],
params=[index_id],
)
更新:我使用 .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])
文档:https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.extra
我有 2 个 Django 模型,ModelA
带有一个 ArrayField
用于存储大量主键值列表(可能超过 50k 个列表)
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()
这个有效:
qs = ModelB.objects.get_for_index(index_id=1)
但是,如果 "pk_values" 是一个大列表,这会非常慢。
所以我尝试进行原始 SQL 查询:
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)
但是这个 returns 一个 django.db.models.query.RawQuerySet
实例。
但是有了这个,我以后就不能做像queryset.values()
这样的事情了。
如何将其转换为普通的 Django 查询集?
有更好的方法吗?
文档:
您可以使用 RawSQL 表达式:
ModelB.objects.filter(id__in=RawSQL(
'SELECT unnest(a.pk_values) FROM app_modela a WHERE a.id = %s',
[index_id]
))
或者,您可以使用 extra():
重现问题中的确切查询ModelB.objects.extra(
tables=['foo_modela'],
where=[
'"app_modelb"."id" = ANY("app_modela"."pk_values")',
'"app_modela"."id" = %s',
],
params=[index_id],
)
更新:我使用 .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])
文档:https://docs.djangoproject.com/en/2.0/ref/models/querysets/#django.db.models.query.QuerySet.extra