如何使用Django ORM进行批量插入或增量类型操作

时间:2014-11-23 02:37:27

标签: python django postgresql

我有一个定义的模型:

class VectorSet(models.Model):
    word = models.CharField(max_length=255)
    weight = models.IntegerField()
    session = models.ForeignKey(ResearchSession)

我想编写一个函数,它将获取单词列表和ResearchSession,如果单词列表中的每个单词都不存在,则创建一个带有权重的新行为1,否则取该行并增加1的重量。

到目前为止,我已经得到了这个:

def train(words, session):
    for i in words:
        result, created = VectorSet.objects.get_or_create(word=i, session=session,
                                                          defaults={'weight' : 1})
        if not created:
            result.weight = F('weight') + 1
            result.save()

我非常确信有一种方法可以通过一个查询来完成此操作但是我无法弄清楚它可能是什么,或者是否可以使用django代码进行原始操作SQL。

2 个答案:

答案 0 :(得分:0)

我认为目前没有开箱即用的解决方案来进行bulk_create以外的批量插入。另一种解决方案(取决于您的数据库)是使用atomic在事务中执行get_or_create。例如:

from django.db import transaction

@transaction.atomic
def train(words, session):
    for i in words:
        result, created = VectorSet.objects.get_or_create(word=i, session=session,
                                                      defaults={'weight' : 1})
        if not created:
            result.weight = F('weight') + 1
            result.save()

否则,您可以使用数据库API executemany

cursor.executemany('INSERT INTO vectorset (field1, field2, field3) VALUES (?, ?, ?)', data)

答案 1 :(得分:0)

逻辑很简单,但是我们需要多次命中DB,这意味着有几个查询:

qs = VectorSet.objects.filter(word__in=words, session=session)
qs.update(weiget=models.F('weight')+1)
VectorSet.objects.bulk_insert(VectorSet(session=session, word=w, weight=1)
  for w in words if w not in qs.value_list('word', flat=True))

Django 1.7中还有一个update_or_create,但目前它没有区分update的默认值和默认值:

for w in words:
    VectorSet.objects.update_or_create(word=w, session=session,
                                    defaults={'weight': models.F('weight')+1})

因此,上述代码将无法通过int(models.F('weight')+1)进行创建(我们可以覆盖__int__方法,但太有意义了...... IMO)