Recarregar objeto django do banco de dados


159

É possível atualizar o estado de um objeto django do banco de dados? Quero dizer comportamento aproximadamente equivalente a:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

ATUALIZAÇÃO: Foi encontrada uma guerra de reabertura / correção de erros no rastreador: http://code.djangoproject.com/ticket/901 . Ainda não entendo por que os mantenedores não gostam disso.


Em um contexto SQL comum, isso não faz sentido. O objeto de banco de dados só pode ser alterado após a conclusão da transação e a commmit. Depois de fazer isso, você terá que aguardar a confirmação da próxima transação SQL. Por que fazer isso? Quanto tempo você espera pela próxima transação?
precisa saber é o seguinte

Isso parece uma função desnecessária; já é possível apenas procurar novamente o objeto no banco de dados.
Stephan

Gostaria que esta bem, mas foi desligado várias vezes aqui
eruciform

2
Não é apropriado porque os objetos de modelo do Django são proxies. Se você obtiver a mesma linha da tabela em dois objetos - x1 = X.objects.get (id = 1); x2 = X.objects.get (id = 1), eles serão testados como iguais, mas são objetos diferentes e o estado não é compartilhado. Você pode alterar os dois independentemente e salvá-los - o último salvo determina o estado da linha no banco de dados. Portanto, é correto recarregar com atribuição simples - x1 = X.objects.get (id = 1). Ter um método de recarga levaria muitas pessoas a inferir erroneamente que x1.f = 'novo valor'; (x1.f == x2.f) é True.
Paul Whipp 06/02

Respostas:


258

A partir do Django 1.8, a atualização de objetos é incorporada. Link para docs .

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

@ fcracker79 Sim, foi implementado apenas no 1.8. Para versões anteriores do Django, é melhor seguir uma das outras respostas.
Tim Fletcher

1
Não sabe o que significa "Todos os campos não diferidos são atualizados" mencionados nos documentos significa?
Yunti 13/11/2015

1
@Yunti Você pode adiar os campos ou solicitar explicitamente apenas um subconjunto de campos, e o objeto resultante será preenchido apenas parcialmente. refresh_from_dbatualizará apenas esses campos já preenchidos.
301_Moved_Permanently

Não foi possível encontrar detalhes nos documentos, mas gera uma DoesNotExistexceção corretamente se o objeto subjacente foi excluído ao chamar refresh_from_db. PARA SUA INFORMAÇÃO.
Tim Tisdall 17/01

28

Achei relativamente fácil recarregar o objeto do banco de dados da seguinte forma:

x = X.objects.get(id=x.id)

19
Sim, mas ... depois disso, você deve atualizar todas as referências a este objeto. Não é muito prático e propenso a erros.
grep

2
Achei isso necessário quando o Celery atualizou meu objeto no db fora do django, aparentemente o django manteve um cache do objeto, pois não fazia ideia de que havia mudado.
precisa saber é o seguinte

3
do django.db.models.loading import get_model; = exemplo get_model (exemplo) .objects.get (pk = instance.pk)
Erik

1
O @grep acabou de perder 2 horas escrevendo um teste para este caso de uso: 1: Inicialize um modelo; 2: Atualize o modelo através de um formulário; 3: Teste se o novo valor está atualizado .... Então, sim, propenso a erros.
Vlad-ardelean

3
Eu acho que refresh_from_dbresolve todos esses problemas.
Flimm

16

Em referência ao comentário do @ grep, não deveria ser possível:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

Obrigado pela solução. Se apenas isso permitisse vários votos positivos!
User590028 de

11
O Django agora fornece refresh_from_dbmétodo.
Flimm

9

Como o @Flimm apontou, esta é uma solução realmente impressionante:

foo.refresh_from_db()

Isso recarrega todos os dados do banco de dados no objeto.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.