2010-12-07 17 views
91

¿Es posible actualizar el estado de un objeto django de la base de datos? Me refiero a un comportamiento más o menos equivalente a:Recargar objeto django desde la base de datos

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

UPD: encontrado una guerra reabrir/wontfix en el perseguidor: http://code.djangoproject.com/ticket/901. Todavía no entiendo por qué a los mantenedores no les gusta esto.

+0

En un contexto SQL ordinario, esto no tiene sentido. El objeto de la base de datos solo se puede cambiar * después de que * finalice su transacción y se realiza un 'commmit'. Una vez que hayas hecho eso, tendrías que esperar a que se realice la siguiente transacción SQL. ¿Por qué hacer eso? ¿Cuánto tiempo vas a esperar para la próxima transacción? –

+0

Esto parece una función innecesaria; ya es posible volver a buscar el objeto de la base de datos. – Stephan

+0

también me gustaría esto, pero se ha cerrado repetidamente [aquí] (http://www.google.com/url?sa=t&source=web&cd=1&ved=0CBkQFjAA&url=https%3A%2F%2Fcode.djangoproject .com% 2Fticket% 2F901 & ei = xOP7TaaCNMv1gAen2pTeCw & usg = AFQjCNFs7kMieML6P8vlIeQplFJpVxQbTA) – eruciform

Respuesta

134

A partir de Django 1.8 refrescar objetos está integrado. Link to 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) 
+0

@ fcracker79 Sí, solo se implementó en 1.8. Para las versiones anteriores de Django, es mejor usar una de las otras respuestas. –

+0

No estoy seguro de qué "Todos los campos no diferidos se actualizan" mencionados en los medios de documentación? – Yunti

25

he encontrado que es relativamente fácil de reload the object from the database así:

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

Sí, pero ... después de eso, debe actualizar todas las referencias a este objeto. No es muy práctico y propenso a errores. – grep

+0

sí, esto no hace nada si la instancia todavía se está transfiriendo, por ejemplo, por una subclase de un ModelForm, de modo que el que finalmente llama a form.instance.save() obtendrá la versión "recargada" – eruciform

+2

Consideró que esto es necesario cuando Aplery actualizó mi objeto en el db fuera de django, django aparentemente guardó un caché del objeto ya que no tenía idea de que había cambiado. –

13

En referencia al comentario de @ grep, ¿no debería ser posible hacerlo:

# 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 
+0

Gracias por la solución. ¡Si solo SO permitiera múltiples votos! – user590028

+2

Django ahora proporciona el método 'refresh_from_db'. – Flimm

Cuestiones relacionadas