Mettez à jour uniquement des champs spécifiques dans un modèle.

92

J'ai un modèle

class Survey(models.Model):
    created_by = models.ForeignKey(User)
    question = models.CharField(max_length=150)
    active = models.NullBooleanField()
    def __unicode__(self):
        return self.question

et maintenant je veux mettre à jour uniquement le activechamp. Alors je fais ceci:

survey = get_object_or_404(Survey, created_by=request.user, pk=question_id)
survey.active = True
survey.save(["active"]) 

Maintenant, j'obtiens une erreur IntegrityError: PRIMARY KEY must be unique.

Ai-je raison avec cette méthode de mise à jour?

Utilisateur enregistré
la source

Réponses:

187

Pour mettre à jour un sous-ensemble de champs, vous pouvez utiliser update_fields:

survey.save(update_fields=["active"]) 

L' update_fieldsargument a été ajouté dans Django 1.5. Dans les versions antérieures, vous pouviez utiliser la update()méthode à la place:

Survey.objects.filter(pk=survey.pk).update(active=True)
Alasdair
la source
17

Généralement, la manière correcte de mettre à jour certains champs dans une ou plusieurs instances de modèle consiste à utiliser la update()méthode sur l'ensemble de requêtes respectif. Ensuite, vous faites quelque chose comme ceci:

affected_surveys = Survey.objects.filter(
    # restrict your queryset by whatever fits you
    # ...
    ).update(active=True)

De cette façon, vous n'avez plus besoin d'appeler save()votre modèle car il est sauvegardé automatiquement. En outre, la update()méthode renvoie le nombre d'instances d'enquête qui ont été affectées par votre mise à jour.

pemistahl
la source
2
Merci. Je l'ai essayé avec .getau lieu de .filteret cela ne fonctionne pas. Mais avec le filtre, cela fonctionne bien. Savez-vous ce qui ne va pas avec mon code ci-dessus?
Utilisateur enregistré
Votre problème peut être lié à question_id. D'où vient cette valeur? Et quelle ligne exacte soulève le IntegrityError?
pemistahl
question_idprovient des URL (?P<question_id>\d+). Ma faute était que sur le serveur de travail, django 1.4 est installé et mon code est 1.5. Mais avec votre code, cela fonctionne bien.
Utilisateur enregistré
2
@RegisteredUser, il semble qu'il n'y ait pas de méthode "update" sur les objets, juste sur les ensembles de requêtes. Lorsque vous utilisez .filter (), vous récupérez un ensemble de requêtes (contenant zéro ou plusieurs objets). Lorsque vous utilisez .get (), vous obtenez un seul objet.
mgojohn
Par défaut, appeler save()(solution @Alasdair) est une solution plus sûre, car cette méthode peut déclencher des choses comme la validation, ou tout autre code personnalisé, que update()ne le fait pas.
David D.