Création en masse d'objets de modèle dans django

90

J'ai beaucoup d'objets à enregistrer dans la base de données et je souhaite donc créer des instances de modèle avec cela.

Avec django, je peux créer toutes les instances de modèles, avec MyModel(data), puis je veux les sauvegarder toutes.

Actuellement, j'ai quelque chose comme ça:

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

Je me demande si je peux enregistrer directement une liste d'objets, par exemple:

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

Comment sauvegarder tous les objets en une seule transaction?

Alexis Métaireau
la source
Il semble que la balle roule sur la mise en œuvre d'un correctif pour ce code.djangoproject.com/ticket/19527
DanH
1
vous vous demandez list.save_all? Vous pourriez presque vous répondre simplement paraphraser cette question et utiliser les deux premiers mots de votre question thématique.
Sławomir Lenart

Réponses:

95

dès le développement de django, il existe en bulk_createtant que méthode de gestion d'objets qui prend en entrée un tableau d'objets créés à l'aide du constructeur de classe. consultez la documentation django

ecbtln
la source
1
Mais rappelez-vous que bulk_create a quelques limitations comme il ne crée pas de clés primaires s'il s'agit d'un champ automatique, ce que save () fait automatiquement.
Hitesh Garg
@HiteshGarg, est-ce toujours vrai de nos jours?
Raydel Miranda
1
@RaydelMiranda, oui c'est toujours vrai. C'est juste là dans la documentation: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
En utilisant Django 3.0.x et je confirme que l'utilisation bulk_create()ne déclenche aucun signal. Je me demande pourquoi.
enchance
42

Utilisez la bulk_create()méthode. C'est désormais standard dans Django.

Exemple:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])
Danil
la source
1
Modifié dans Django 1.10: la prise en charge de la définition des clés primaires sur les objets créés à l'aide de bulk_create () lors de l'utilisation de PostgreSQL a été ajoutée.
elad silver
4

a travaillé pour moi pour utiliser la gestion manuelle des transactions pour la boucle (postgres 9.1):

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

en fait ce n'est pas la même chose que l'insertion en masse d'une base de données `` native '', mais cela vous permet d'éviter / de réduire les opérations de transport / orms / requête SQL analyser les coûts

Eviltnan
la source
1
Cela a légèrement changé. Maintenant, la transaction n'a commit_on_successplus. Vous devriez utiliser transaction.atomic()See: stackoverflow.com/questions/21861207/…
t_io
4

Voici comment créer en bloc des entités à partir d'un fichier séparé par colonne, en laissant de côté toutes les routines sans guillemets et sans échappement:

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
la source
3

pour une implémentation sur une seule ligne, vous pouvez utiliser une expression lambda dans une carte

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

Ici, lambda fait correspondre chaque élément de la liste d'éléments à x et crée un enregistrement de base de données si nécessaire.

Documentation Lambda

Ange déchu
la source
Vous voudrez probablement mentionner que le lambdadoit être mapterminé items:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Manoj Govindan
Ja, c'est une autre façon que j'essaie de dire (:
FallenAngel
2

L'utilisation de create provoquera une requête par nouvel élément. Si vous souhaitez réduire le nombre de requêtes INSERT, vous devrez utiliser autre chose.

J'ai eu un certain succès en utilisant l'extrait Bulk Insert, même si l'extrait est assez ancien. Il y a peut-être des changements nécessaires pour qu'il fonctionne à nouveau.

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

OmerGertel
la source
2

Consultez ce billet de blog sur le module bulkops .

Sur mon application django 1.3, j'ai connu une accélération significative.

MrJ
la source
-19

Le moyen le plus simple consiste à utiliser la createméthode Manager, qui crée et enregistre l'objet en une seule étape.

for item in items:
    MyModel.objects.create(name=item.name)
Daniel Roseman
la source
+1. Si namedes entrées uniques et dupliquées sont possibles, ce serait une bonne idée à utiliser get_or_create.
Manoj Govindan
16
Comment cela répond-il à la question? Model.objects.create équivaut à object = MoModel (..) object.save (). Et cela ne le fait pas en une seule transaction ...
automagic