Criar objetos de modelo em massa no Django

92

Tenho muitos objetos para salvar no banco de dados e, por isso, quero criar instâncias de Model com isso.

Com django, posso criar todas as instâncias de modelos, com MyModel(data), e depois quero salvá-los todos.

Atualmente, tenho algo assim:

for item in items:
    object = MyModel(name=item.name)
    object.save()

Estou me perguntando se posso salvar uma lista de objetos diretamente, por exemplo:

objects = []
for item in items:
    objects.append(MyModel(name=item.name))
objects.save_all()

Como salvar todos os objetos em uma transação?

Alexis Métaireau
fonte
Parece que a bola está rolando na implementação de uma correção para este code.djangoproject.com/ticket/19527
DanH
1
pensando em list.save_all? Você quase poderia responder a si mesmo apenas parafraseando essa pergunta e usando as 2 primeiras palavras de sua pergunta de tópico.
Sławomir Lenart

Respostas:

99

a partir do desenvolvimento do django, existe bulk_createcomo um método gerenciador de objetos que recebe como entrada um array de objetos criados usando o construtor de classe. verifique a documentação do django

ecbtln
fonte
13
Documentos do Django para bulk_create: docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create
funkotron
1
Mas lembre-se que bulk_create tem algumas limitações, como não cria chaves primárias se for um AutoField que save () faz automaticamente.
Hitesh Garg
@HiteshGarg, isso ainda é verdade hoje em dia?
Raydel Miranda
1
@RaydelMiranda, sim, ainda é verdade. Está bem ali na documentação:If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does, unless the database backend supports it (currently only PostgreSQL).
interDist
1
Usando Django 3.0.xe eu confirmo que o uso bulk_create()não dispara nenhum sinal. Eu quero saber porque.
enchance
43

Use o bulk_create()método. É padrão no Django agora.

Exemplo:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])
Danil
fonte
1
Alterado no Django 1.10: Foi adicionado suporte para definir chaves primárias em objetos criados usando bulk_create () ao usar PostgreSQL.
elad silver
4

funcionou para mim usar o tratamento manual de transações para o loop (postgres 9.1):

from django.db import transaction
with transaction.commit_on_success():
    for item in items:
        MyModel.objects.create(name=item.name)

na verdade, não é o mesmo que inserção em massa de banco de dados "nativo", mas permite que você evite / diminua os custos de transporte / operações orms / análise de consulta sql

Eviltnan
fonte
1
Isso mudou ligeiramente. Agora a transação não tem commit_on_successmais. Você deve usar transaction.atomic()See: stackoverflow.com/questions/21861207/…
t_io
4

Aqui está como criar entidades em massa a partir de arquivos separados por colunas, deixando de lado todas as rotinas de unquoting e un-escape:

SomeModel(Model):
    @classmethod
    def from_file(model, file_obj, headers, delimiter):
        model.objects.bulk_create([
            model(**dict(zip(headers, line.split(delimiter))))
            for line in file_obj],
            batch_size=None)
Ivan Klass
fonte
3

para uma implementação de linha única, você pode usar uma expressão lambda em um mapa

map(lambda x:MyModel.objects.get_or_create(name=x), items)

Aqui, lambda corresponde a cada item na lista de itens com x e cria um registro de banco de dados, se necessário.

Documentação Lambda

Anjo caído
fonte
Você provavelmente vai querer mencionar que o lambdatem de ser mapped sobre items:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Manoj Govindan
Sim, essa é outra maneira que tento dizer (:
FallenAngel
2

O uso de criar causará uma consulta por novo item. Se você deseja reduzir o número de consultas INSERT, você precisará usar outra coisa.

Tive algum sucesso usando o snippet Bulk Insert, embora o snippet seja bastante antigo. Talvez haja algumas mudanças necessárias para fazê-lo funcionar novamente.

http://djangosnippets.org/snippets/446/

OmerGertel
fonte
2

Confira esta postagem do blog sobre o módulo bulkops .

No meu aplicativo django 1.3, experimentei uma aceleração significativa.

MrJ
fonte
-20

A maneira mais fácil é usar o createmétodo Manager, que cria e salva o objeto em uma única etapa.

for item in items:
    MyModel.objects.create(name=item.name)
Daniel Roseman
fonte
+1. Se namefor único e forem possíveis entradas duplicadas, é uma boa ideia usar get_or_create.
Manoj Govindan
16
Como isso responde à pergunta? Model.objects.create é equivalente a object = MoModel (..) object.save (). E isso não acontece em uma transação ...
automagic