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?


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



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")
])

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


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)

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


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/


2

Consultez ce billet de blog sur le module bulkops .

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


-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)

+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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.