2016-04-20 26 views
4

我正在使用Django 1.9。我有一个Django的表按月份表示特定措施的价值,通过组织,原始值和百分位数:在Django中一次更新多个对象?

class MeasureValue(models.Model): 
    org = models.ForeignKey(Org, null=True, blank=True) 
    month = models.DateField() 
    calc_value = models.FloatField(null=True, blank=True) 
    percentile = models.FloatField(null=True, blank=True) 

通常有1万名左右每月。我的问题是关于我是否可以加快在模型上设置值的过程。

目前,我通过使用Django过滤器查询检索一个月的所有度量值,将其转换为熊猫数据框,然后使用scipy的rankdata来设置等级和百分位数来计算百分比。我这样做是因为大熊猫rankdata是有效的,可以忽略空值,并且能够在我所希望的方式来处理重复的值,所以我很高兴用这种方法:

records = MeasureValue.objects.filter(month=month).values() 
df = pd.DataFrame.from_records(records) 
// use calc_value to set percentile on each row, using scipy's rankdata 

不过,我需要再从数据框中检索每个百分位数值,并将其设置回模型实例。现在,我这样做是通过遍历数据帧中的行,并更新每个实例:

for i, row in df.iterrows(): 
    mv = MeasureValue.objects.get(org=row.org, month=month) 
    if (row.percentile is None) or np.isnan(row.percentile): 
     row.percentile = None 
    mv.percentile = row.percentile 
    mv.save() 

这是勿庸置疑相当缓慢。是否有任何有效的Django方式来加速它,通过使单个数据库写入而不是成千上万?我有checked the documentation,但看不到一个。

+0

你看过['QuerySet.update()'](https://docs.djangoproject.com/en/1.9/ref/models/querysets/#update)吗? –

+0

@ Two-BitAlchemist我不确定它有帮助,因为我需要为每一行设置不同的值......? – Richard

+0

哦,我错过了这个要求,对不起 –

回答

8

原子事务可以减少循环所用时间:

from django.db import transaction 

with transaction.atomic(): 
    for i, row in df.iterrows(): 
     mv = MeasureValue.objects.get(org=row.org, month=month) 

     if (row.percentile is None) or np.isnan(row.percentile): 
      # if it's already None, why set it to None? 
      row.percentile = None 

     mv.percentile = row.percentile 
     mv.save() 

Django的默认行为是在自动提交模式下运行。每个查询都会立即提交给数据库,除非事务处于活动状态。通过使用with transaction.atomic()所有插入被分组到单个事务中。提交事务所需的时间将在所有随附的插入语句中摊销,因此每个插入语句的时间会大大减少。

+0

谢谢。为什么这会缩短时间?该文件不帮助https://docs.djangoproject.com/en/1.9/topics/db/transactions/#controlling-transactions-explyly – Richard

+0

检查我的更新 – ahmed