210

Is it possible to refresh the state of a django object from database? I mean behavior roughly equivalent to:

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

UPDATE: Found a reopen/wontfix war in the tracker: http://code.djangoproject.com/ticket/901. Still don't understand why the maintainers don't like this.

Harry Moreno
  • 10,231
  • 7
  • 64
  • 116
Maxim Razin
  • 9,114
  • 7
  • 34
  • 33
  • In an ordinary SQL context, this doesn't make sense. The database object can only be changed *after* your transaction finishes and does a `commmit`. Once you've done that, you'd have to wait around for the next SQL transaction to commit. Why do that? How long are you going to wait for the next transaction? – S.Lott Dec 07 '10 at 15:55
  • This seems like a needless function; it's already possible to just re-look-up the object from the database. – Stephan Dec 07 '10 at 18:10
  • i would like this as well, but it has been shut down repeatedly [here](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 Jun 17 '11 at 23:34
  • 2
    It is not appropriate because Django model objects are proxies. If you get the same table row into two objects - x1 = X.objects.get(id=1); x2 = X.objects.get(id=1), they will test as equal but they are different objects and state is not shared. You can change both independently and save them - the last one saved determines the state of the row in the database. Therefore it is correct to reload with simple assignment - x1 = X.objects.get(id=1). Having a reload method would lead to many people wrongly inferring that x1.f = 'new value'; (x1.f == x2.f) is True. – Paul Whipp Feb 06 '14 at 20:49

4 Answers4

351

As of Django 1.8 refreshing objects is built in. 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)
Tim Fletcher
  • 7,062
  • 1
  • 35
  • 33
  • @fcracker79 Yeah, it was only implemented in 1.8. For earlier versions of Django you're best going with one of the other answers. – Tim Fletcher Aug 25 '15 at 15:46
  • 1
    Not sure what "All non-deferred fields are updated "mentioned in the docs means? – Yunti Nov 13 '15 at 18:15
  • 1
    @Yunti You can [defer](https://docs.djangoproject.com/en/1.8/ref/models/querysets/#defer) fields, or explicitly ask for [only a subset](https://docs.djangoproject.com/en/1.8/ref/models/querysets/#only) of fields and the resulting object will be only partially populated. `refresh_from_db` will only update such already populated fields. – 301_Moved_Permanently Jan 16 '19 at 16:37
  • Couldn't find details in the docs, but it properly throws a `DoesNotExist` exception if the underlying object was deleted when calling `refresh_from_db`. FYI. – Tim Tisdall Jan 17 '20 at 19:26
31

I've found it relatively easy to reload the object from the database like so:

x = X.objects.get(id=x.id)
Amandasaurus
  • 58,203
  • 71
  • 188
  • 248
  • 22
    Yes, but... after that you have to update all references to this object. Not very handy and error-prone. – Maxim Razin Feb 04 '11 at 14:12
  • yes, this does nothing if the instance is still being passed around, for example by a subclass of a ModelForm, such that the one finally calling form.instance.save() will get the "reloaded" version – eruciform Jun 17 '11 at 23:38
  • 4
    Found this to be necessary when Celery updated my object in the db outside of django, django apparently kept a cache of the object since it had no idea it had changed. – Bob Spryn Aug 21 '12 at 06:16
  • 3
    from django.db.models.loading import get_model; instance = get_model(instance).objects.get(pk=instance.pk) – Erik May 31 '13 at 22:22
  • Also problematic if the id field is one of the fields that is out of sync. – Rachel K. Westmacott Aug 19 '13 at 14:33
  • @PeterWestmacott well, quite often it's really good practice to have immutable primary key field, let it be "id", or something else. Exceptions to the rule exist, of course. – Olli Nov 23 '13 at 14:55
  • 1
    @grep just lost 2 hours writing a test for this use case: 1: Initialize a model; 2: Update the Model via a Form; 3: Test that the new value is updated.... So yeah, error prone. – vlad-ardelean Oct 06 '14 at 09:06
  • 5
    I think `refresh_from_db` solves all these problems. – Flimm Jan 05 '17 at 13:47
25

As @Flimm pointed out, this is a really awesome solution:

foo.refresh_from_db()

This reloads all data from the database into the object.

Ron
  • 22,128
  • 31
  • 108
  • 206
18

In reference to @grep's comment, shouldn't it be possible to do:

# 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
Eloff
  • 20,828
  • 17
  • 83
  • 112