【问题标题】:Django ORM - Annotate Query with another SubQuery while keeping the results of SubQueryDjango ORM - 用另一个子查询注释查询,同时保留子查询的结果
【发布时间】:2021-07-12 07:46:10
【问题描述】:
#  My Database Models
ModelA(models.Model):
    referancer = models.CharField()
    ...
        
ModelXYZ(models.Model):
    name = models.CharField()
    ...

我有像 top 这样的模型,它们之间没有外键关系,结构也应该保持这种方式,因为在我的实际查询中;过滤器和注释比这个更复杂。这也是重现问题的最简单方法。

modelXYZ_subquery = ModelXYZ.objects.filter(name__exact=OuterRef('referancer')).order_by('-id')
modelA_dataset = ModelA.objects.filter(**my_custom_filters).annotate(
    has_XYZ=Exists(modelXYZ_subquery),
    latest_xyz=Subquery(modelXYZ_subquery.values('id')[:1], output_field=IntegerField)
)

for _modelA in modelA_dataset:
    my_custom_function_1(_modelA)
    if _modelA.has_XYZ:
        detected_xyz = ModelXYZ.objects.get(id=_modelA.latest_xyz) # Database Hit
    else:
        detected_xyz = create_xyz(_modelA)
    my_custom_function_2(_modelA, detected_xyz)

这是我得到的功能,但由于数据集庞大,它的工作时间太长了。

我想摆脱我在 for 循环中获得的不必要的数据库命中。

有没有办法通过 annotationprefetch_related 或其他东西来实现这个目标?

【问题讨论】:

  • 为什么referancer这个字段不是ForeignKey
  • 这不是我的选择,数据库结构应该保持这种状态。只是想加快我在下面得到的功能。

标签: mysql django orm prefetch annotate


【解决方案1】:

您可以考虑使用JoinField。这不会改变您的数据库结构,但会允许 ORM 以与外键相同的方式进行连接。 pip install django-joinfield 并将 joinfield 放入 settings.py 中的 INSTALLED_APPS

from joinfield.joinfield import JoinField

class ModelXYZ(models.Model):
    name = JoinField(ModelA, to_field='referancer', on_delete=models.DO_NOTHING)

makemigrations 将创建一个迁移,但迁移不会改变您的数据库结构。将允许 ModelXYZ.name 中具有 ModelA.referancer 中不存在的值。

现在您可以从 ModelA 到 ModelXYZ 执行 prefetch_related

【讨论】:

  • 我会等待赏金的最后一天。如果没有更好的答案,那么我将编辑我的问题并将其批准为答案先生。
猜你喜欢
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 2020-01-18
  • 2019-10-13
相关资源
最近更新 更多