J'aimerais mettre à jour une table avec Django - quelque chose comme ceci dans le SQL brut:
update tbl_name set name = 'foo' where name = 'bar'
Mon premier résultat est quelque chose comme ça - mais c'est méchant, n'est-ce pas?
list = ModelClass.objects.filter(name = 'bar')
for obj in list:
obj.name = 'foo'
obj.save()
Y a-t-il un moyen plus élégant?
Reportez-vous à la section suivante de la documentation Django
En bref, vous devriez pouvoir utiliser:
ModelClass.objects.filter(name='bar').update(name="foo")
Vous pouvez également utiliser des objets F
pour incrémenter des lignes, par exemple:
from Django.db.models import F
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
Voir la documentation: https://docs.djangoproject.com/fr/1.9/topics/db/queries/
Cependant, notez que:
ModelClass.save
(donc si vous avez une logique à l'intérieur, elle ne sera pas déclenchée). Pensez à utiliser Django-bulk-update
trouvé ici sur GitHub .
Installer: pip install Django-bulk-update
Implement: (code extrait directement du fichier ReadMe du projet)
from bulk_update.helper import bulk_update
random_names = ['Walter', 'The Dude', 'Donny', 'Jesus']
people = Person.objects.all()
for person in people:
r = random.randrange(4)
person.name = random_names[r]
bulk_update(people) # updates all columns using the default db
Mise à jour: Comme le souligne Marc dans les commentaires, cela ne convient pas pour mettre à jour des milliers de lignes à la fois. Bien qu’il soit adapté aux plus petits lots de 10 à 100. La taille du lot qui vous convient dépend de la complexité de votre processeur et de vos requêtes. Cet outil ressemble plus à une brouette qu'à un camion à benne basculante.
La version Django 2.2 a maintenant une méthode bulk_update
( notes de version ).
https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-update
Exemple:
# get a pk: record dictionary of existing records
updates = YourModel.objects.filter(...).in_bulk()
....
# do something with the updates dict
....
if hasattr(YourModel.objects, 'bulk_update') and updates:
# Use the new method
YourModel.objects.bulk_update(updates.values(), [list the fields to update], batch_size=100)
else:
# The old & slow way
with transaction.atomic():
for obj in updates.values():
obj.save(update_fields=[list the fields to update])
Si vous souhaitez définir la même valeur sur une collection de lignes , vous pouvez utiliser la méthode update () combinée à tout terme de la requête pour mettre à jour toutes les lignes d'une requête:
some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)
Si vous souhaitez mettre à jour une collection de lignes avec des valeurs différentes selon certaines conditions, vous pouvez dans le meilleur des cas regrouper les mises à jour en fonction de valeurs. Supposons que vous avez 1 000 lignes pour lesquelles vous souhaitez définir une colonne sur l'une des valeurs X, vous pouvez alors préparer les lots à l'avance, puis n'exécuter que X requêtes de mise à jour (chacune ayant essentiellement la forme du premier exemple ci-dessus) + le SELECT initial -question.
Si chaque ligne requiert une valeur unique il n'y a aucun moyen d'éviter une requête par mise à jour. Peut-être devriez-vous vous tourner vers d'autres architectures, telles que CQRS/Event Sourcing, si vous avez besoin de performances dans ce dernier cas.