Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

rjnocelli
Copy link

@rjnocelli rjnocelli commented Oct 12, 2025

Trac ticket number

ticket-5815

Branch description

At the moment there is not an 'easy' way to invalidate cached view responses from Django code. This PR introduces an utility function called invalidate_view_cache which allows you to do so using the relative path (request object takes care of putting together the rest of the URL).

Checklist

  • This PR targets the main branch.
  • The commit message is written in past tense, mentions the ticket number, and ends with a period.
  • I have checked the "Has patch" ticket flag in the Trac system.
  • I have added or updated relevant tests.
  • I have added or updated relevant docs, including release notes if applicable.
  • I have attached screenshots in both light and dark modes for any UI changes.

Copy link

Hello! Thank you for your contribution 💪

As it's your first contribution be sure to check out the patch review checklist.

If you're fixing a ticket from Trac make sure to set the "Has patch" flag and include a link to this PR in the ticket!

If you have any design or process questions then you can ask in the Django forum.

Welcome aboard ⛵️!

@rjnocelli rjnocelli force-pushed the invalidate_cache_key_function branch from db53bae to 063c5ee Compare October 12, 2025 17:22
…ction to manually invalidate cache key.

Thanks Laurent Tramoy for the implementation idea and Carlton Gibson for
the support.
@rjnocelli rjnocelli force-pushed the invalidate_cache_key_function branch from 063c5ee to 20e2676 Compare October 12, 2025 17:26
@carltongibson
Copy link
Member

Hey @rjnocelli — Welcome aboard! ⛵️— Nice hustle turning your work into a PR over the weekend. (You can assign the ticket to yourself on Trac 🙂)

Let me read it through and give an initial feedback. (We don't currently use type annotations in Django itself, so we'll drop those, and docs would be needed, etc — but we can refine towards all that.)

Nice one! 👊

Copy link
Member

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @rjnocelli — I had a first look.

Can you add some test cases for the vary_header argument, showing that in action?

We'll need then to adjust the docstring a little and add docs, but seems pretty straightforward. Nice 👍

Comment on lines 466 to 468
vary_headers should be a dict of every header used for this particular view
In local environment, we have two defined renderers (default of DRF),
thus DRF adds `Accept` to the Vary headers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjnocelli Can you add tests showing this in action?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, definitely!

Comment on lines 454 to 458
path: str = None,
request: WSGIRequest = None,
vary_headers: Optional[Dict[str, str]] = None,
key_prefix: Optional[str] = None,
) -> Annotated[int, "Number of cache keys deleted"]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove the annotations.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, will do!

Comment on lines 473 to 474
Note: If LocaleMiddleware is used,
we'll need to use the same language code as the one in the cached request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs a test case too.

Copy link
Author

@rjnocelli rjnocelli Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both the decorator and get_cache_key function rely on the same underlying logic in _generate_cache_key which accounts for configuration settings.USE_I18N. Since this logic is implicit to the generation and retrieval of the cache key in this workflow, is a test really needed here? It might make sense to add to possibility to delete all locale variations of a key (something similar to what Laurent Tramoy propposed on ticket 31938) but this will require more work since not all cache backends support key search by pattern (I think Redis scan function would work for this).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, not sure immediately. Maybe a test isn't needed...

I was mostly thinking for the docs. We're going to need to give examples for folks to know how to use this function, and given that it's worth a comment, it's probably worth an examples too.

(Start with the normal vary versions and then we can see what docs we come up with)

@rjnocelli
Copy link
Author

I've applied some new changes:

  • removed typing
  • removed function parameters which I think are not relevant for the scope of this implementation
  • added documentation
  • added two new tests to cover cases for Vary headers and key prefix missmatch

Copy link
Member

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @rjnocelli. I've just left a few more discursive comments. (They're status Maybe 🤔 rather than more than that.)

I checked the flag on the ticket: looking good. Ready for a review from someone else now.

(I'm really excited about this. I'm going to have to pull it into my personal project so that I can stop flushing my cache entirely every time I spot a typo 💃)

Comment on lines 386 to 387
If there is no headerlist stored, the page needs to be rebuilt, so this
function returns ``None``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unrelated. Could either be dropped or merged as a separate clean up. (Pending Fellow decisions)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll roll this one back.

Comment on lines 451 to 452
Delete a view cache key based on either a relative URL (``path``)
or a request object (``request``).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does "view cache" relate to cache_page clearly enough? Maybe...

Suggested change
Delete a view cache key based on either a relative URL (``path``)
or a request object (``request``).
Delete a cached page key based on either a relative URL (``path``)
or a request object (``request``).

return t[0].lower(), True


def invalidate_view_cache(path=None, request=None, key_prefix=None, cache=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we want just a request parameter, which could be a path, then converted in the same code block as below? 🤔

If both are given, ``path`` takes precedence.
"""
if not request:
assert path is not None, "either `path` or `request` arguments needed"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raise a ValueError (?) here, and test for the exception. (Rather than an assertion, to match Django code style.)

@rjnocelli
Copy link
Author

rjnocelli commented Oct 16, 2025

Hi @carltongibson! Here are few comments regarding my latest changes:

  • I've removed path parameter. Now request parameter accepts a HttpRequest object or a relative path. Regarding the latter, I've noticed that the request factory "stringyfies" any path/url type so it is very unlikely for it to rise a ValueError therefore I don't see the value of adding a testcase for this. Obviously passing a dict or list as path does not make sense at all so it is down to the user to call the function with the proper types.
  • I've rolled back get_cache_key documentation to it's original one.
  • I've added a new test using a ASGIRequest instead of a WSGIRequest. Please let me know if this does not add value at all and I'll remove it.

Looking forward hearing back from you! cheers!

@carltongibson
Copy link
Member

Great. good effort @rjnocelli.

I want to wait for someone else to take a look now. It's in the right ballpark, but other eyes. I looked at the flags on Trac, and they were set right, so this ticket will appear on the review queue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.