Skip to content

Commit

Permalink
fix: Cache not invalidated when using a PlaceholderField outside the …
Browse files Browse the repository at this point in the history
…CMS #6912 (#6956)

* FIX(cache): Placeholder cache clearing
Force placeholder cache clearing when updating a PlaceholderField content

* TESTS: Render Placeholderfield with cache

Add a test to check that the mark_as_dirty method of placeholder will clear placeholder cache for custom model having a Placeholderfield and edited from the cms.admin.placeholderadmin methods

* DOCS: Update changelog:
- Add a changelog line for PlaceholderField cache invalidation fix

Co-authored-by: Benjamin PIERRE <bp@kapt.mobi>
Co-authored-by: Vinit Kumar <mail@vinitkumar.me>
Co-authored-by: Florian Delizy <florian.delizy@gmail.com>
  • Loading branch information
4 people committed May 19, 2021
1 parent 52f926e commit 3ce63d7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Expand Up @@ -9,6 +9,7 @@ Unreleased
* Fixed builds on RTD
* Remove debug print from apphook_reload
* Enforce use of coverage > 4 for python 3.8 support
* Fixed the cache not being invalidated when updating a PlaceholderField in a custom model
* Fixed 66622 bad Title.path in multilingual sites when parent slug is created or modified
* Fixed 6973 bag with unexpected behavior ``get_page_from_request``
* Temporarily pinned django-treebeard to < 4.5, this avoids breaking changes introduced
Expand Down
4 changes: 4 additions & 0 deletions cms/models/placeholdermodel.py
Expand Up @@ -507,6 +507,10 @@ def mark_as_dirty(self, language, clear_cache=True):
elif attached_model is StaticPlaceholder:
StaticPlaceholder.objects.filter(draft=self).update(dirty=True)

# Force to clear cache when attached model is not a Page or a StaticPlaceholder, otherwise cache is never invalidated when using PlaceholderField
elif clear_cache is False:
self.clear_cache(language)

def get_plugin_tree_order(self, language, parent_id=None):
"""
Returns a list of plugin ids matching the given language
Expand Down
53 changes: 53 additions & 0 deletions cms/tests/test_cache.py
Expand Up @@ -653,6 +653,59 @@ def test_render_placeholder_cache(self):
text = content_renderer.render_placeholder(ph1, context)
self.assertEqual(text, "Other text")

def test_render_placeholderfield_cache_in_custom_model(self):
"""
Regression test for #6912
Assert that placeholder of a placeholderfield in custom model has its cache cleared correctly when mark_as_dirty is called in the admin
"""

invalidate_cms_page_cache()

# Create an instance of a custom model containing a placeholderfield
ex = Example1(char_1="one", char_2="two", char_3="tree", char_4="four")
ex.save()
ph1 = ex.placeholder

# Add a first plugin
test_plugin = add_plugin(ph1, "TextPlugin", "en", body="Some text")
test_plugin.save()

# Create a first request using render_placeholder to ensure that the content is equal to the first plugin content
request = self.get_request()
content_renderer = self.get_content_renderer(request)
context = SekizaiContext()
context["request"] = self.get_request()
text = content_renderer.render_placeholder(ph1, context, use_cache=True)
self.assertEqual(text, "Some text")

# Add a second plugin in the placeholder
test_plugin = add_plugin(ph1, "TextPlugin", "en", body="Some other text")
test_plugin.save()

# Clear plugins cache to ensure that cms.utils.plugins.get_plugins() will refetch the plugins
del ph1._plugins_cache

# Create a second request using render_placeholder to ensure that the content is still equal to the first plugin content as cache was not cleared yet
request = self.get_request()
content_renderer = self.get_content_renderer(request)
context = SekizaiContext()
context["request"] = self.get_request()
text = content_renderer.render_placeholder(ph1, context, use_cache=True)
self.assertEqual(text, "Some text")

# Mark placeholder as dirty as it is done in cms.admin.placeholderadmin file
ph1.mark_as_dirty("en", clear_cache=False)

# Create a last request to ensure that rendered content contains the two plugins content
request = self.get_request()
content_renderer = self.get_content_renderer(request)
context = SekizaiContext()
context["request"] = self.get_request()

text = content_renderer.render_placeholder(ph1, context, use_cache=True)
self.assertEqual(text, "Some textSome other text")


class PlaceholderCacheTestCase(CMSTestCase):
def setUp(self):
Expand Down

0 comments on commit 3ce63d7

Please sign in to comment.