Aktualizuj tylko określone pola w modelu

92

Mam modelkę

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

a teraz chcę zaktualizować tylko activepole. Więc robię to:

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

Teraz pojawia się błąd IntegrityError: PRIMARY KEY must be unique.

Czy mam rację z tą metodą aktualizacji?

zarejestrowany użytkownik
źródło

Odpowiedzi:

187

Aby zaktualizować podzbiór pól, możesz użyć update_fields:

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

update_fieldsArgumentu dodano Django 1.5. We wcześniejszych wersjach można było update()zamiast tego użyć metody:

Survey.objects.filter(pk=survey.pk).update(active=True)
Alasdair
źródło
17

Zwykle prawidłowym sposobem aktualizowania niektórych pól w co najmniej jednym wystąpieniu modelu jest użycie rozszerzenia update() metody w odpowiednim zestawie zapytań. Następnie robisz coś takiego:

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

W ten sposób nie musisz już dzwonić save()do swojego modelu, ponieważ jest on zapisywany automatycznie. Ponadto update()metoda zwraca liczbę wystąpień ankiety, na które wpłynęła aktualizacja.

pemistahl
źródło
2
Dzięki. Próbowałem z .getzamiast .filteri to nie działa. Ale z filtrem działa dobrze. Czy wiesz, co jest nie tak z moim kodem powyżej?
Zarejestrowany użytkownik
Twój problem może być związany z question_id. Skąd ta wartość? A która dokładnie linia podnosi IntegrityError?
pemistahl
question_idpochodzi z adresów URL (?P<question_id>\d+). Moja wina polegała na tym, że na działającym serwerze jest zainstalowane django 1.4, a mój kod to 1.5. Ale z twoim kodem działa dobrze.
Zarejestrowany użytkownik
2
@RegisteredUser, wygląda na to, że nie ma metody "update" na obiektach, tylko na querysets. Kiedy używasz .filter (), otrzymujesz z powrotem zestaw zapytań (zawierający zero lub więcej obiektów). Kiedy używasz .get (), otrzymujesz pojedynczy obiekt.
mgojohn
Domyślnie wywołanie save()(rozwiązanie @Alasdair) jest bezpieczniejszym rozwiązaniem, ponieważ ta metoda może wyzwalać takie rzeczy, jak walidacja lub dowolny niestandardowy kod, niż update()nie.
David D.