Crie o modelo Django ou atualize se houver

114

Eu quero criar um objeto modelo, como Pessoa, se o id da pessoa não existir, ou vou pegar esse objeto pessoa.

O código para criar uma nova pessoa da seguinte forma:

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

Mas não sei onde verificar e obter o objeto de pessoa existente.

user1687717
fonte

Respostas:

169

Se você está procurando o caso de uso "atualizar se existir, criar", consulte @Zags excelente resposta


Django já tem um get_or_create, https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

Para você, poderia ser:

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
fonte
Estou usando o django 1.9, e ele está me fornecendo: AttributeError: O objeto 'QuerySet' não tem atributo 'update_or_create'
Ofek Gila
1
@OfekGila Isso é estranho, tanto o código fonte ea documentação de confirmação QuerySettemupdate_or_create
Bakkal
2
No meu caso, no lugar do identificador, tenho um grupo de campos que forma unique_together. Como é o uso para este caso?
Rakmo
191

Não está claro se sua pergunta é sobre o método get_or_create (disponível pelo menos no Django 1.3) ou o método update_or_create (novo no Django 1.7). Depende de como você deseja atualizar o objeto de usuário.

O uso da amostra é o seguinte:

# 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
fonte
12
+1 para update_or_createporque, para esse caso de uso, é melhor do que get_or_createapenas chamar save()o objeto novamente.
bakkal de
No meu caso, no lugar do identificador, tenho um grupo de campos que forma unique_together. Como é o uso para este caso?
Rakmo
1
O identificador @OmkarDeshpande é apenas um exemplo; você pode passar em qualquer consulta django válida, comoPerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags
E se eu quiser adicionar mais campos à Pessoa criada do que os padrões?
Lo Bellin
@LoBellin o defaultsargumento para essas funções é onde você especifica quais campos deseja adicionar ao modelo. Não tem nada a ver com os padrões especificados nos campos do seu modelo
Zags
10

Django tem suporte para isso, verifique 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
fonte
4

Para apenas uma pequena quantidade de objetos, update_or_create funciona bem, mas se você estiver fazendo sobre uma grande coleção, ele não escalará bem. update_or_create sempre executa primeiro um SELECT e depois um 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)

Na melhor das hipóteses, isso só executará a primeira consulta de atualização e apenas se corresponder a zero linhas, execute outra consulta INSERT. O que aumentará muito seu desempenho se você espera que a maioria das linhas realmente exista.

Porém, tudo se resume ao seu caso de uso. Se você está esperando principalmente inserções, talvez o comando bulk_create () possa ser uma opção.

Andreas Bergström
fonte
3

Pensei em adicionar uma resposta, já que o título da pergunta parece que pergunta como criar ou atualizar, em vez de obter ou criar conforme descrito no corpo da pergunta.

Se você deseja criar ou atualizar um objeto, o método .save () já tem este comportamento por padrão, a partir dos documentos :

Django abstrai a necessidade de usar instruções SQL INSERT ou UPDATE. Especificamente, quando você chama save (), o Django segue este algoritmo:

Se o atributo de chave primária do objeto é definido com um valor que avalia como True (ou seja, um valor diferente de None ou a string vazia), o Django executa um UPDATE. Se o atributo da chave primária do objeto não estiver definido ou se o UPDATE não atualizou nada, o Django executa um INSERT.

É importante notar que quando eles dizem 'se o UPDATE não atualizou nada' eles estão essencialmente se referindo ao caso em que o id que você forneceu ao objeto ainda não existe no banco de dados.

Tom Manterfield
fonte
1

Se uma das entradas ao criar for uma chave primária, isso será o suficiente:

Person.objects.get_or_create(id=1)

Ele será atualizado automaticamente se existir, pois dois dados com a mesma chave primária não são permitidos.

Aminah Nuraini
fonte