Utwórz model Django lub zaktualizuj, jeśli istnieje

115

Chcę utworzyć obiekt modelowy, taki jak Osoba, jeśli identyfikator osoby nie istnieje, lub otrzymam obiekt tej osoby.

Kod do utworzenia nowej osoby w następujący sposób:

class Person(models.Model):
    identifier = models.CharField(max_length = 10)
    name = models.CharField(max_length = 20)
    objects = PersonManager()

class PersonManager(models.Manager):
    def create_person(self, identifier):
        person = self.create(identifier = identifier)
        return person

Ale nie wiem, gdzie sprawdzić i pobrać istniejący obiekt osoby.

user1687717
źródło

Odpowiedzi:

169

Jeśli szukasz przypadku użycia „aktualizacja, jeśli istnieje, utwórz”, zapoznaj się z doskonałą odpowiedzią @Zags


Django ma już get_or_create, https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

Dla Ciebie może to być:

id = 'some identifier'
person, created = Person.objects.get_or_create(identifier=id)

if created:
   # means you have created a new person
else:
   # person just refers to the existing one
bakkal
źródło
Używam Django 1.9, a to daje mi: AttributeError: obiekt „queryset” nie ma atrybutu „update_or_create”
Ofek Gila
1
@OfekGila To dziwne, zarówno kod źródłowy , jak i dokumentacja potwierdzają, QuerySetże takupdate_or_create
bakkal
2
W moim przypadku zamiast identyfikatora mam grupę pól, które razem tworzą unikalne. Jak wygląda użycie w tym przypadku?
Rakmo
192

Nie jest jasne, czy twoje pytanie dotyczy metody get_or_create (dostępnej co najmniej od Django 1.3) czy metody update_or_create (nowość w Django 1.7). To zależy od tego, jak chcesz zaktualizować obiekt użytkownika.

Przykładowe użycie jest następujące:

# In both cases, the call will get a person object with matching
# identifier or create one if none exists; if a person is created,
# it will be created with name equal to the value in `name`.

# In this case, if the Person already exists, its existing name is preserved
person, created = Person.objects.get_or_create(
        identifier=identifier, defaults={"name": name}
)

# In this case, if the Person already exists, its name is updated
person, created = Person.objects.update_or_create(
        identifier=identifier, defaults={"name": name}
)
Zags
źródło
12
+1 za, update_or_createponieważ w tym przypadku użycia lepiej niż get_or_createpo prostu ponownie wywołać save()obiekt.
bakkal
W moim przypadku zamiast identyfikatora mam grupę pól, które razem tworzą unikalne. Jak wygląda użycie w tym przypadku?
Rakmo
1
Identyfikator @OmkarDeshpande to tylko przykład; możesz przekazać dowolne prawidłowe zapytanie django, takie jakPerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags
Co jeśli chcę dodać więcej pól do utworzonej osoby niż domyślne?
Lo Bellin
@LoBellin defaultsargumentem tych funkcji jest miejsce, w którym określasz, jakie pola chcesz dodać do modelu. Nie ma to nic wspólnego z wartościami domyślnymi określonymi w polach twojego modelu
Zags
10

Django obsługuje to, sprawdź get_or_create

person, created = Person.objects.get_or_create(name='abc')
if created:
    # A new person object created
else:
    # person object already exists
Aamir Adnan
źródło
4

Tylko w przypadku niewielkiej liczby obiektów update_or_create działa dobrze, ale jeśli robisz na dużej kolekcji, nie będzie dobrze skalować. update_or_create zawsze najpierw uruchamia SELECT, a następnie UPDATE.

for the_bar in bars:
    updated_rows = SomeModel.objects.filter(bar=the_bar).update(foo=100)
        if not updated_rows:
            # if not exists, create new
            SomeModel.objects.create(bar=the_bar, foo=100)

W najlepszym przypadku spowoduje to uruchomienie tylko pierwszego zapytania aktualizującego i tylko wtedy, gdy pasuje do zerowych wierszy, uruchomi kolejne zapytanie INSERT. Co znacznie zwiększy wydajność, jeśli spodziewasz się, że większość wierszy faktycznie istnieje.

Wszystko sprowadza się jednak do twojego przypadku użycia. Jeśli spodziewasz się głównie wstawień, być może polecenie bulk_create () może być opcją.

Andreas Bergström
źródło
3

Pomyślałem, że dodam odpowiedź, ponieważ tytuł twojego pytania wygląda tak, jakby pytał, jak utworzyć lub zaktualizować, zamiast pobierać lub tworzyć zgodnie z opisem w treści pytania.

Jeśli chcesz utworzyć lub zaktualizować obiekt, metoda .save () ma już to zachowanie domyślnie, z dokumentów :

Django abstrahuje od potrzeby używania instrukcji INSERT lub UPDATE SQL. W szczególności, gdy wywołujesz save (), Django postępuje zgodnie z tym algorytmem:

Jeśli atrybut klucza podstawowego obiektu jest ustawiony na wartość, której wynikiem jest True (tj. Wartość inna niż None lub pusty łańcuch), Django wykonuje UPDATE. Jeśli atrybut klucza podstawowego obiektu nie jest ustawiony lub jeśli UPDATE niczego nie zaktualizował, Django wykonuje INSERT.

Warto zauważyć, że kiedy mówią „jeśli UPDATE niczego nie zaktualizował”, zasadniczo odnoszą się do przypadku, w którym identyfikator, który nadałeś obiektowi, nie istnieje już w bazie danych.

Tom Manterfield
źródło
1

Jeśli jednym z danych wejściowych podczas tworzenia jest klucz podstawowy, wystarczy:

Person.objects.get_or_create(id=1)

Zaktualizuje się automatycznie, jeśli istnieje, ponieważ dwa dane z tym samym kluczem podstawowym są niedozwolone.

Aminah Nuraini
źródło