prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Cache does not get invalidated correctly when LanguageTreeNode is deleted
  ### Describe the Bug
  <!-- A clear and concise description of what the bug is. -->
  If you delete a language the page tree still shows the translation status of the corresponding language. This is probably a caching issue.
  
  Cache does not get invalidated correctly when LanguageTreeNode is deleted
  ### Describe the Bug
  <!-- A clear and concise description of what the bug is. -->
  If you delete a language the page tree still shows the translation status of the corresponding language. This is probably a caching issue.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `integreat_cms/cms/views/language_tree/language_tree_actions.py`
  Content:
  ```
  1 """
  2 This module contains view actions for the language tree.
  3 Typically, they do not render a whole page, but only parts of it or they redirect to regular views.
  4 """
  5 import logging
  6 
  7 from django.contrib import messages
  8 from django.shortcuts import redirect, get_object_or_404
  9 from django.utils.translation import ugettext as _
  10 from django.views.decorators.http import require_POST
  11 from django.db import transaction
  12 
  13 from treebeard.exceptions import InvalidPosition, InvalidMoveToDescendant
  14 
  15 from ...constants import position
  16 from ...decorators import permission_required
  17 from ...models import LanguageTreeNode
  18 
  19 logger = logging.getLogger(__name__)
  20 
  21 
  22 @require_POST
  23 @permission_required("cms.change_languagetreenode")
  24 @transaction.atomic
  25 def move_language_tree_node(
  26     request, region_slug, language_tree_node_id, target_id, target_position
  27 ):
  28     """
  29     This action moves the given language tree node to the given position relative to the given target.
  30 
  31     :param request: The current request
  32     :type request: ~django.http.HttpResponse
  33 
  34     :param region_slug: The slug of the region which language tree should be modified
  35     :type region_slug: str
  36 
  37     :param language_tree_node_id: The id of the language tree node which should be moved
  38     :type language_tree_node_id: int
  39 
  40     :param target_id: The id of the target language tree node
  41     :type target_id: int
  42 
  43     :param target_position: The desired position (choices: :mod:`~integreat_cms.cms.constants.position`)
  44     :type target_position: str
  45 
  46     :return: A redirection to the language tree
  47     :rtype: ~django.http.HttpResponseRedirect
  48     """
  49 
  50     region = request.region
  51     language_tree_node = get_object_or_404(
  52         region.language_tree_nodes, id=language_tree_node_id
  53     )
  54     target = get_object_or_404(region.language_tree_nodes, id=target_id)
  55 
  56     try:
  57         if target.depth == 1 and target_position in [position.LEFT, position.RIGHT]:
  58             raise InvalidPosition(_("A region can only have one root language."))
  59         language_tree_node.move(target, target_position)
  60         # Call the save method on the (reloaded) node in order to trigger possible signal handlers etc.
  61         # (The move()-method executes raw sql which might cause problems if the instance isn't fetched again)
  62         language_tree_node = LanguageTreeNode.objects.get(id=language_tree_node_id)
  63         language_tree_node.save()
  64         messages.success(
  65             request,
  66             _('The language tree node "{}" was successfully moved.').format(
  67                 language_tree_node.translated_name
  68             ),
  69         )
  70         logger.debug(
  71             "%r moved to %r of %r by %r",
  72             language_tree_node,
  73             target_position,
  74             target,
  75             request.user,
  76         )
  77     except (ValueError, InvalidPosition, InvalidMoveToDescendant) as e:
  78         messages.error(request, e)
  79         logger.exception(e)
  80 
  81     return redirect("language_tree", **{"region_slug": region_slug})
  82 
  83 
  84 @require_POST
  85 @permission_required("cms.delete_languagetreenode")
  86 @transaction.atomic
  87 def delete_language_tree_node(request, region_slug, language_tree_node_id):
  88     """
  89     Deletes the language node of distinct region
  90     and all page translations for this language
  91 
  92     :param request: The current request
  93     :type request: ~django.http.HttpResponse
  94 
  95     :param region_slug: The slug of the region which language node should be deleted
  96     :type region_slug: str
  97 
  98     :param language_tree_node_id: The id of the language tree node which should be deleted
  99     :type language_tree_node_id: int
  100 
  101     :return: A redirection to the language tree
  102     :rtype: ~django.http.HttpResponseRedirect
  103     """
  104     # get current region
  105     region = request.region
  106     # get current selected language node
  107     language_node = get_object_or_404(
  108         region.language_tree_nodes, id=language_tree_node_id
  109     )
  110     # get all page translation assigned to the language node
  111     page_translations = language_node.language.page_translations
  112     # filter those translation that belong to the region and delete them
  113     page_translations.filter(page__region=region).delete()
  114     # get all event translation assigned to the language node
  115     event_translations = language_node.language.event_translations
  116     # filter those translation that belong to the region and delete them
  117     event_translations.filter(event__region=region).delete()
  118     # get all poi translation assigned to the language node
  119     poi_translations = language_node.language.poi_translations
  120     # filter those translation that belong to the region and delete them
  121     poi_translations.filter(poi__region=region).delete()
  122     # get all push notification translation assigned to the language node
  123     push_notification_translations = (
  124         language_node.language.push_notification_translations
  125     )
  126     # filter those translation that belong to the region and delete them
  127     push_notification_translations.filter(push_notification__region=region).delete()
  128 
  129     logger.debug("%r deleted by %r", language_node, request.user)
  130     language_node.delete()
  131     messages.success(
  132         request,
  133         _(
  134             'The language tree node "{}" and all corresponding translations were successfully deleted.'
  135         ).format(language_node.translated_name),
  136     )
  137     return redirect("language_tree", **{"region_slug": region_slug})
  138
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/integreat_cms/cms/views/language_tree/language_tree_actions.py b/integreat_cms/cms/views/language_tree/language_tree_actions.py
  --- a/integreat_cms/cms/views/language_tree/language_tree_actions.py
  +++ b/integreat_cms/cms/views/language_tree/language_tree_actions.py
  @@ -11,6 +11,7 @@
   from django.db import transaction
   
   from treebeard.exceptions import InvalidPosition, InvalidMoveToDescendant
  +from cacheops import invalidate_obj
   
   from ...constants import position
   from ...decorators import permission_required
  @@ -128,6 +129,16 @@
   
       logger.debug("%r deleted by %r", language_node, request.user)
       language_node.delete()
  +
  +    for page in region.pages.all():
  +        invalidate_obj(page)
  +    for event in region.events.all():
  +        invalidate_obj(event)
  +    for poi in region.pois.all():
  +        invalidate_obj(poi)
  +    for push_notification in region.push_notifications.all():
  +        invalidate_obj(push_notification)
  +
       messages.success(
           request,
           _(
  
verification_info: {"golden_diff": "diff --git a/integreat_cms/cms/views/language_tree/language_tree_actions.py b/integreat_cms/cms/views/language_tree/language_tree_actions.py\n--- a/integreat_cms/cms/views/language_tree/language_tree_actions.py\n+++ b/integreat_cms/cms/views/language_tree/language_tree_actions.py\n@@ -11,6 +11,7 @@\n from django.db import transaction\n \n from treebeard.exceptions import InvalidPosition, InvalidMoveToDescendant\n+from cacheops import invalidate_obj\n \n from ...constants import position\n from ...decorators import permission_required\n@@ -128,6 +129,16 @@\n \n     logger.debug(\"%r deleted by %r\", language_node, request.user)\n     language_node.delete()\n+\n+    for page in region.pages.all():\n+        invalidate_obj(page)\n+    for event in region.events.all():\n+        invalidate_obj(event)\n+    for poi in region.pois.all():\n+        invalidate_obj(poi)\n+    for push_notification in region.push_notifications.all():\n+        invalidate_obj(push_notification)\n+\n     messages.success(\n         request,\n         _(\n", "issue": "Cache does not get invalidated correctly when LanguageTreeNode is deleted\n### Describe the Bug\r\n<!-- A clear and concise description of what the bug is. -->\r\nIf you delete a language the page tree still shows the translation status of the corresponding language. This is probably a caching issue.\r\n\nCache does not get invalidated correctly when LanguageTreeNode is deleted\n### Describe the Bug\r\n<!-- A clear and concise description of what the bug is. -->\r\nIf you delete a language the page tree still shows the translation status of the corresponding language. This is probably a caching issue.\r\n\n", "before_files": [{"content": "\"\"\"\nThis module contains view actions for the language tree.\nTypically, they do not render a whole page, but only parts of it or they redirect to regular views.\n\"\"\"\nimport logging\n\nfrom django.contrib import messages\nfrom django.shortcuts import redirect, get_object_or_404\nfrom django.utils.translation import ugettext as _\nfrom django.views.decorators.http import require_POST\nfrom django.db import transaction\n\nfrom treebeard.exceptions import InvalidPosition, InvalidMoveToDescendant\n\nfrom ...constants import position\nfrom ...decorators import permission_required\nfrom ...models import LanguageTreeNode\n\nlogger = logging.getLogger(__name__)\n\n\n@require_POST\n@permission_required(\"cms.change_languagetreenode\")\n@transaction.atomic\ndef move_language_tree_node(\n    request, region_slug, language_tree_node_id, target_id, target_position\n):\n    \"\"\"\n    This action moves the given language tree node to the given position relative to the given target.\n\n    :param request: The current request\n    :type request: ~django.http.HttpResponse\n\n    :param region_slug: The slug of the region which language tree should be modified\n    :type region_slug: str\n\n    :param language_tree_node_id: The id of the language tree node which should be moved\n    :type language_tree_node_id: int\n\n    :param target_id: The id of the target language tree node\n    :type target_id: int\n\n    :param target_position: The desired position (choices: :mod:`~integreat_cms.cms.constants.position`)\n    :type target_position: str\n\n    :return: A redirection to the language tree\n    :rtype: ~django.http.HttpResponseRedirect\n    \"\"\"\n\n    region = request.region\n    language_tree_node = get_object_or_404(\n        region.language_tree_nodes, id=language_tree_node_id\n    )\n    target = get_object_or_404(region.language_tree_nodes, id=target_id)\n\n    try:\n        if target.depth == 1 and target_position in [position.LEFT, position.RIGHT]:\n            raise InvalidPosition(_(\"A region can only have one root language.\"))\n        language_tree_node.move(target, target_position)\n        # Call the save method on the (reloaded) node in order to trigger possible signal handlers etc.\n        # (The move()-method executes raw sql which might cause problems if the instance isn't fetched again)\n        language_tree_node = LanguageTreeNode.objects.get(id=language_tree_node_id)\n        language_tree_node.save()\n        messages.success(\n            request,\n            _('The language tree node \"{}\" was successfully moved.').format(\n                language_tree_node.translated_name\n            ),\n        )\n        logger.debug(\n            \"%r moved to %r of %r by %r\",\n            language_tree_node,\n            target_position,\n            target,\n            request.user,\n        )\n    except (ValueError, InvalidPosition, InvalidMoveToDescendant) as e:\n        messages.error(request, e)\n        logger.exception(e)\n\n    return redirect(\"language_tree\", **{\"region_slug\": region_slug})\n\n\n@require_POST\n@permission_required(\"cms.delete_languagetreenode\")\n@transaction.atomic\ndef delete_language_tree_node(request, region_slug, language_tree_node_id):\n    \"\"\"\n    Deletes the language node of distinct region\n    and all page translations for this language\n\n    :param request: The current request\n    :type request: ~django.http.HttpResponse\n\n    :param region_slug: The slug of the region which language node should be deleted\n    :type region_slug: str\n\n    :param language_tree_node_id: The id of the language tree node which should be deleted\n    :type language_tree_node_id: int\n\n    :return: A redirection to the language tree\n    :rtype: ~django.http.HttpResponseRedirect\n    \"\"\"\n    # get current region\n    region = request.region\n    # get current selected language node\n    language_node = get_object_or_404(\n        region.language_tree_nodes, id=language_tree_node_id\n    )\n    # get all page translation assigned to the language node\n    page_translations = language_node.language.page_translations\n    # filter those translation that belong to the region and delete them\n    page_translations.filter(page__region=region).delete()\n    # get all event translation assigned to the language node\n    event_translations = language_node.language.event_translations\n    # filter those translation that belong to the region and delete them\n    event_translations.filter(event__region=region).delete()\n    # get all poi translation assigned to the language node\n    poi_translations = language_node.language.poi_translations\n    # filter those translation that belong to the region and delete them\n    poi_translations.filter(poi__region=region).delete()\n    # get all push notification translation assigned to the language node\n    push_notification_translations = (\n        language_node.language.push_notification_translations\n    )\n    # filter those translation that belong to the region and delete them\n    push_notification_translations.filter(push_notification__region=region).delete()\n\n    logger.debug(\"%r deleted by %r\", language_node, request.user)\n    language_node.delete()\n    messages.success(\n        request,\n        _(\n            'The language tree node \"{}\" and all corresponding translations were successfully deleted.'\n        ).format(language_node.translated_name),\n    )\n    return redirect(\"language_tree\", **{\"region_slug\": region_slug})\n", "path": "integreat_cms/cms/views/language_tree/language_tree_actions.py"}], "after_files": [{"content": "\"\"\"\nThis module contains view actions for the language tree.\nTypically, they do not render a whole page, but only parts of it or they redirect to regular views.\n\"\"\"\nimport logging\n\nfrom django.contrib import messages\nfrom django.shortcuts import redirect, get_object_or_404\nfrom django.utils.translation import ugettext as _\nfrom django.views.decorators.http import require_POST\nfrom django.db import transaction\n\nfrom treebeard.exceptions import InvalidPosition, InvalidMoveToDescendant\nfrom cacheops import invalidate_obj\n\nfrom ...constants import position\nfrom ...decorators import permission_required\nfrom ...models import LanguageTreeNode\n\nlogger = logging.getLogger(__name__)\n\n\n@require_POST\n@permission_required(\"cms.change_languagetreenode\")\n@transaction.atomic\ndef move_language_tree_node(\n    request, region_slug, language_tree_node_id, target_id, target_position\n):\n    \"\"\"\n    This action moves the given language tree node to the given position relative to the given target.\n\n    :param request: The current request\n    :type request: ~django.http.HttpResponse\n\n    :param region_slug: The slug of the region which language tree should be modified\n    :type region_slug: str\n\n    :param language_tree_node_id: The id of the language tree node which should be moved\n    :type language_tree_node_id: int\n\n    :param target_id: The id of the target language tree node\n    :type target_id: int\n\n    :param target_position: The desired position (choices: :mod:`~integreat_cms.cms.constants.position`)\n    :type target_position: str\n\n    :return: A redirection to the language tree\n    :rtype: ~django.http.HttpResponseRedirect\n    \"\"\"\n\n    region = request.region\n    language_tree_node = get_object_or_404(\n        region.language_tree_nodes, id=language_tree_node_id\n    )\n    target = get_object_or_404(region.language_tree_nodes, id=target_id)\n\n    try:\n        if target.depth == 1 and target_position in [position.LEFT, position.RIGHT]:\n            raise InvalidPosition(_(\"A region can only have one root language.\"))\n        language_tree_node.move(target, target_position)\n        # Call the save method on the (reloaded) node in order to trigger possible signal handlers etc.\n        # (The move()-method executes raw sql which might cause problems if the instance isn't fetched again)\n        language_tree_node = LanguageTreeNode.objects.get(id=language_tree_node_id)\n        language_tree_node.save()\n        messages.success(\n            request,\n            _('The language tree node \"{}\" was successfully moved.').format(\n                language_tree_node.translated_name\n            ),\n        )\n        logger.debug(\n            \"%r moved to %r of %r by %r\",\n            language_tree_node,\n            target_position,\n            target,\n            request.user,\n        )\n    except (ValueError, InvalidPosition, InvalidMoveToDescendant) as e:\n        messages.error(request, e)\n        logger.exception(e)\n\n    return redirect(\"language_tree\", **{\"region_slug\": region_slug})\n\n\n@require_POST\n@permission_required(\"cms.delete_languagetreenode\")\n@transaction.atomic\ndef delete_language_tree_node(request, region_slug, language_tree_node_id):\n    \"\"\"\n    Deletes the language node of distinct region\n    and all page translations for this language\n\n    :param request: The current request\n    :type request: ~django.http.HttpResponse\n\n    :param region_slug: The slug of the region which language node should be deleted\n    :type region_slug: str\n\n    :param language_tree_node_id: The id of the language tree node which should be deleted\n    :type language_tree_node_id: int\n\n    :return: A redirection to the language tree\n    :rtype: ~django.http.HttpResponseRedirect\n    \"\"\"\n    # get current region\n    region = request.region\n    # get current selected language node\n    language_node = get_object_or_404(\n        region.language_tree_nodes, id=language_tree_node_id\n    )\n    # get all page translation assigned to the language node\n    page_translations = language_node.language.page_translations\n    # filter those translation that belong to the region and delete them\n    page_translations.filter(page__region=region).delete()\n    # get all event translation assigned to the language node\n    event_translations = language_node.language.event_translations\n    # filter those translation that belong to the region and delete them\n    event_translations.filter(event__region=region).delete()\n    # get all poi translation assigned to the language node\n    poi_translations = language_node.language.poi_translations\n    # filter those translation that belong to the region and delete them\n    poi_translations.filter(poi__region=region).delete()\n    # get all push notification translation assigned to the language node\n    push_notification_translations = (\n        language_node.language.push_notification_translations\n    )\n    # filter those translation that belong to the region and delete them\n    push_notification_translations.filter(push_notification__region=region).delete()\n\n    logger.debug(\"%r deleted by %r\", language_node, request.user)\n    language_node.delete()\n\n    for page in region.pages.all():\n        invalidate_obj(page)\n    for event in region.events.all():\n        invalidate_obj(event)\n    for poi in region.pois.all():\n        invalidate_obj(poi)\n    for push_notification in region.push_notifications.all():\n        invalidate_obj(push_notification)\n\n    messages.success(\n        request,\n        _(\n            'The language tree node \"{}\" and all corresponding translations were successfully deleted.'\n        ).format(language_node.translated_name),\n    )\n    return redirect(\"language_tree\", **{\"region_slug\": region_slug})\n", "path": "integreat_cms/cms/views/language_tree/language_tree_actions.py"}]}