【发布时间】:2020-03-29 02:43:44
【问题描述】:
我有 4 个模型:
class Run(models.Model):
start_time = models.DateTimeField(db_index=True)
end_time = models.DateTimeField()
chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
recipe = models.ForeignKey(Recipe, default=None, blank=True, null=True, on_delete=models.CASCADE)
class RunProperty(models.Model):
run = models.ForeignKey(Run, on_delete=models.CASCADE)
property_name = models.CharField(max_length=50)
property_value = models.CharField(max_length=500)
class RunValue(models.Model):
run = models.ForeignKey(Run, on_delete=models.CASCADE)
run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
value = models.FloatField(default=0)
class RunParameter(models.Model):
parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)
chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
param_name_user_defined = models.BooleanField(default=True)
一个Run 可以有任意数量的RunProperty(通常是用户定义的属性,可以是自定义的)和一些预定义的RunValue(例如平均电压、最小电压、最大电压),它们是数值。
RunParameter 基本上只是一个包含参数名称(电压、电流、频率、温度、阻抗、振荡、可变性等)的容器。
当我构建一个前端表以显示每个 Run 及其所有“文件”RunProperty(Run 的来源)及其所有“电压”RunValue 时,我首先查询所有 Run 对象的数据库,然后对 Min/Max/Avg 执行另外 3 个查询,然后对 File 执行另一个查询,然后我在后端构建一个 dict 以传递到前端以构建表行:
runs = Run.objects.filter(chamber__in=chambers)
min_v_run_values = RunValue.objects.filter(run__in=runs, run_parameter__parameter__parameter_name__icontains="Minimum Voltage")
max_v_run_values = RunValue.objects.filter(run__in=runs, run_parameter__parameter__parameter_name__icontains="Maximum Voltage")
avg_v_run_values = RunValue.objects.filter(run__in=runs, run_parameter__parameter__parameter_name__icontains="Average Voltage")
run_files = RunProperty.objects.filter(run__in=runs, property_name="File")
对于在他们的数据库中有大约 10 到 30 个 Run 对象的客户来说,这不是一个大问题,但是我们有一个使用量很大的客户,他有 3500 个 Run 实例。不用说,它太慢了。我正在执行 5 次查询以获取所有需要的实例,然后我必须循环并将它们放在一个字典中。为一位客户执行此操作需要超过 45 秒(而对于大多数其他客户,大约需要 8 或 10 秒)。
有没有一种方法可以查询我的数据库中的所有Run 对象以及所有最小/最大/平均电压RunValue 和文件RunProperty 并返回,比如说,一个字典列表,一个对于每个 Run 以及其他对象?
我认为Q 查询可以在这里使用,但我不太确定如何使用它们,或者它们是否适用于这种情况?
我试过了(但没走多远):
runs = Run.objects.filter(chamber__in=chambers)
v_query = Q(run_parameter__parameter__parameter_name__icontains="Voltage")
run_values = RunValue.objects.filter(run__in=runs).filter(v_query)
run_files = RunProperty.objects.filter(run__in=runs, property_name="File")
这让我在 1 个查询中获得了所有 RunValue 相关对象,但每个查询仍然是 3 个。如果可能的话,我需要进一步优化。
我正在寻找类似的东西:
runs = Run.objects.filter(chamber__in=chambers)
.annotate(Q(run__runvalue__run_parameter__parameter__parameter_name__icontains="Voltage")
& Q(run__runproperty__property_name__icontains="File"))
我认为从广义上讲(甚至不是伪代码)我需要这样的查询:
"获取所有Runs,并且对于每个Run,获取与该Run 相关的所有RunValue 对象,这些对象包含["Average"、"Maximum"、"Minimum"] 以及所有包含“文件”的 Run 的 RunProperty 对象。
我不知道这是否可能(听起来应该是),我不确定是否应该使用 Q 过滤、聚合或注释。从广义上讲,如果可能,我需要在一个查询中获取一个模型的所有实例,以及每个实例的所有外键
例子:
我有表 Run 有 2 个实例:
R1
R2
每个Run 实例都有一个关联的 RunProperty 实例“文件”(只是一个字符串):
R1_run.dat
R2_run.dat
每个Run 实例都有很多 RunValue 实例(我以 Voltage 为例,但有 26 个):
R1_max_v
R1_min_v
R1_avg_v
R2_max_v
R2_min_v
R2_avg_v
我需要查询数据库以使其返回(列表或字典,我都可以解决):
[{R1, R1_run.dat, R1_max_v, R1_min_v, R1_avg_v},
{R2, R2_run.dat, R2_max_v, R2_min_v, R2_avg_v}]
甚至是二维数组:
[[R1, R1_run.dat, R1_max_v, R1_min_v, R1_avg_v],
[R2, R2_run.dat, R2_max_v, R2_min_v, R2_avg_v]]
这可能吗?
【问题讨论】:
-
使用annotate、select_related和prefetch_related。
-
我一直在阅读更多关于此的内容,我相信这是我必须做的,查询
Run并注释其他 2 个表。我只是不知道该怎么做。 -
你想要平均电压,但你在模型中提到过。
-
哦,平均值已经计算好了。它直接存储在自己的表中。它是从一个完全不同的表中计算出来的,并且需要经常访问,所以我们决定创建
RunValue表来存储每个Run的 Avg/Max/Min,以免每次都通过 annotate 函数计算这些值。 -
你能显示这个模型“RunParameter”吗
标签: python django postgresql django-queryset