Crea un modello Django o aggiorna se esiste


115

Voglio creare un oggetto modello, come Persona, se l'id della persona non esiste, o otterrò quell'oggetto persona.

Il codice per creare una nuova persona come segue:

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

Ma non so dove controllare e ottenere l'oggetto persona esistente.

Risposte:


169

Se stai cercando il caso d'uso "aggiorna se esiste altrimenti crea", fai riferimento alla risposta eccellente di @Zags


Django ha già un get_or_create, https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

Per te potrebbe essere:

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

Sto usando django 1.9 e mi dà: AttributeError: l'oggetto 'QuerySet' non ha attributo 'update_or_create'
Ofek Gila

1
@OfekGila Questo è strano, sia il codice sorgente e la documentazione di conferma QuerySethaupdate_or_create
Bakkal

2
Nel mio caso, al posto dell'identificatore, ho un gruppo di campi che forma univoco_tutto insieme. Come è l'utilizzo per questo caso?
Rakmo

191

Non è chiaro se la tua domanda chieda il metodo get_or_create (disponibile almeno da Django 1.3) o il metodo update_or_create (nuovo in Django 1.7). Dipende da come si desidera aggiornare l'oggetto utente.

L'uso di esempio è il seguente:

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

12
+1 per update_or_createperché in quel caso d'uso è meglio che get_or_createrichiamare save()nuovamente l'oggetto.
bakkal

Nel mio caso, al posto dell'identificatore, ho un gruppo di campi che forma univoco_tutto insieme. Come è l'utilizzo per questo caso?
Rakmo

1
L'identificatore @OmkarDeshpande è solo un esempio; puoi passare qualsiasi query django valida, comePerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags

E se volessi aggiungere più campi alla Persona creata rispetto a quelli predefiniti?
Lo Bellin

@LoBellin l' defaultsargomento di queste funzioni è dove specifichi quali campi vuoi aggiungere al modello. Non ha nulla a che fare con i valori predefiniti specificati nei campi del modello
Zags

10

Django ha il supporto per questo, controlla get_or_create

person, created = Person.objects.get_or_create(name='abc')
if created:
    # A new person object created
else:
    # person object already exists

4

Solo per una piccola quantità di oggetti update_or_create funziona bene, ma se stai facendo su una grande raccolta non si ridimensionerà bene. update_or_create esegue sempre prima un SELECT e successivamente un 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)

Nella migliore delle ipotesi, eseguirà solo la prima query di aggiornamento e solo se corrisponde a zero righe eseguirà un'altra query INSERT. Il che aumenterà notevolmente le tue prestazioni se ti aspetti che la maggior parte delle righe sia effettivamente esistente.

Tuttavia, tutto dipende dal tuo caso d'uso. Se ti aspetti principalmente inserimenti, forse il comando bulk_create () potrebbe essere un'opzione.


3

Ho pensato di aggiungere una risposta poiché il titolo della tua domanda sembra chiedere come creare o aggiornare, piuttosto che ottenere o creare come descritto nel corpo della domanda.

Se desideri creare o aggiornare un oggetto, il metodo .save () ha già questo comportamento per impostazione predefinita, dai documenti :

Django astrae la necessità di utilizzare istruzioni SQL INSERT o UPDATE. Nello specifico, quando chiami save (), Django segue questo algoritmo:

Se l'attributo della chiave primaria dell'oggetto è impostato su un valore che restituisce True (cioè un valore diverso da None o dalla stringa vuota), Django esegue un UPDATE. Se l'attributo della chiave primaria dell'oggetto non è impostato o se UPDATE non ha aggiornato nulla, Django esegue un INSERT.

Vale la pena notare che quando dicono "se l'AGGIORNAMENTO non ha aggiornato nulla" si riferiscono essenzialmente al caso in cui l'id che hai fornito all'oggetto non esiste già nel database.


1

Se uno degli input in fase di creazione è una chiave primaria, questo sarà sufficiente:

Person.objects.get_or_create(id=1)

Si aggiornerà automaticamente se esiste poiché due dati con la stessa chiave primaria non sono consentiti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.