Suor / django-cacheops

A slick ORM cache with automatic granular event-driven invalidation.
BSD 3-Clause "New" or "Revised" License
2.1k stars 227 forks source link

exclude vs filter , has differences? #415

Closed moonseoklee closed 1 year ago

moonseoklee commented 2 years ago

It seems that the filter and exclude(also !Q) do not work the same. In short, if the value of the join target field is changed when performing the join filter, the filter reflects the new cache, but the exclude responds to the old cache without reflecting the new cache.

for example

`

    ticket = Ticket.objects.exclude(contents__status=Content.Status.END)

    print(ticket)

    ticket = Ticket.objects.exclude(contents__status=Content.Status.END).nocache()

    print(ticket)

    ticket = Ticket.objects.filter(contents__status=Content.Status.END)

    print(ticket)

    ticket = Ticket.objects.filter(contents__status=Content.Status.END).nocache()

    print(ticket)

`

When the status of the content changes, two queries using 'filter' (cache, nocache) produce the same results, but two queries using 'exclude' produce different results. That is, the 'exclude'' does not reflect the latest content.status values.

Table relation is as follows.

` class Content: pass

class Ticket: contents = manytomanyfield `

Cache ops setting is follows. ` CACHEOPS = { 'content_app.Ticket': {'ops': 'all', 'timeout': 6000},

'content_app.Content': {'ops': 'all', 'timeout': 6000}, } `

Did I miss anything in the document? I know that when the joinfilter target is changed, it can lead to performance degradation by updating the entire query cache, but this issue is different from what I expected. Is there anything I missed that filter and exclude work differently?

Thank you.

Suor commented 2 years ago

So .exclude() fails to invalidate? Can you create a test for this? There is an instruction in the end of README.

moonseoklee commented 2 years ago

I made a pull request. Thanks!

moonseoklee commented 2 years ago

Additionally, cache invalidation works on Ticket.save. But dont works on Content.save