modelname_set.all() returning cached state

When using modelname_set.all() I am having issues where it isn’t returning the most recently added entries added to the database.

Here is a code example to show the problem (although I can’t recreate the issue it in a Django shell):

a = ModelA(text="test"))
a.save()
ModelA.objects.all()
<QuerySet [<ModelA: test>]>

# ...

b = ModelB(a=a, text="test")
b.save()
a.modelb_set.all()
<QuerySet [<ModelB: test>]>

# ...

b = ModelB(a=a, text="test2")
b.save()
a.modelb_set.all()
<QuerySet [<ModelB: test>]>

# ...

b = ModelB(a=a, text="test3")
b.save()
a.modelb_set.all()
<QuerySet [<ModelB: test>, <ModelB: test2>]>

I have found two solutions to this issue that work:

  1. Using ModelB.objects.filter(modela=modela) instead of _set.all().
  2. Using modela.refresh_from_db() just after saving the instance of ModelB so that modelb_set.all() returns the most recent records.

I have read that _set.all() should be unaffected by caching, although this is clearly not the case here. Can anyone here tell me why it might be returning outdated results?

Hi jp438,

I’d suggest reviewing the docs on this. You’re likely evaluating the queryset and reusing that instance which will use the cached values.

I believe another way to force a DB hit is to call queryset.filter() with nothing passed in.

Let me know if things are unclear after reviewing the docs.

-Tim

Hi Tim,

Thanks for the reply! If I am understanding it correctly I don’t think this is the issue as I am creating the ModelB instance in a function on ModelA (using self as the foreign key) and then further down the same function calling another function on self that accesses the _set. Here is a clearer demonstration of how it is structured in my code:

class ModelA:
    def fn():
        # ...
        b = ModelB(a=self, text="test")
        b.save()
        # self.refresh_from_db() # fixes the issue
        # ...
        self.otherFn()
        # ...

    def otherFn():
        # ...
        self.modelb_set.all() # Outdated results
        # ModelB.objects.filter(modela=self) # Up to date results
        # ...

The first time it works perfectly (presumably because there is no cache), but if I run fn() a second time it will only give the content added the first time, and a third time will give the contents from the first and second time and so on…

Or am I misunderstanding and self (a result from a query) due to caching is an instance in time and a new instance needs to be created, or it needs to be reloaded from the database, before any changes can be seen on self (although testing this concept in a shell on a demo django project an that doesn’t seem to replicate the issue).

Hi jp438,

I’m unable to reproduce this with some generic models in a view or a shell. Can you share your full functions? There may be something else that’s going on that’s causing the issue. Additionally, did you change any settings regarding transactions? What database are you using?

-Tim