prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Pragma no cache for path graph json
  As in https://github.com/makinacorpus/django-mapentity/pull/48
  
  Related https://github.com/makinacorpus/Geotrek/issues/1026
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `geotrek/core/views.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 import json
  3 from django.http import HttpResponse
  4 from django.utils.decorators import method_decorator
  5 from django.contrib.auth.decorators import login_required
  6 from django.views.decorators.http import last_modified as cache_last_modified
  7 from django.views.generic.edit import BaseDetailView
  8 from django.core.cache import get_cache
  9 from django.shortcuts import redirect
  10 
  11 from mapentity.views import (MapEntityLayer, MapEntityList, MapEntityJsonList,
  12                              MapEntityDetail, MapEntityDocument, MapEntityCreate, MapEntityUpdate,
  13                              MapEntityDelete, MapEntityFormat,
  14                              JSONResponseMixin, HttpJSONResponse, LastModifiedMixin)
  15 
  16 from geotrek.authent.decorators import path_manager_required, same_structure_required
  17 
  18 from .models import Path, Trail
  19 from .forms import PathForm
  20 from .filters import PathFilter
  21 from . import graph as graph_lib
  22 
  23 
  24 @login_required
  25 def last_list(request):
  26     last = request.session.get('last_list')  # set in MapEntityList
  27     if not last:
  28         return redirect('core:path_list')
  29     return redirect(last)
  30 
  31 home = last_list
  32 
  33 
  34 class HttpSVGResponse(HttpResponse):
  35     content_type = 'image/svg+xml'
  36     def __init__(self, content='', **kwargs):
  37         kwargs['content_type'] = self.content_type
  38         super(HttpSVGResponse, self).__init__(content, **kwargs)
  39 
  40 
  41 class ElevationChart(LastModifiedMixin, BaseDetailView):
  42 
  43     @method_decorator(login_required)
  44     def dispatch(self, *args, **kwargs):
  45         return super(ElevationChart, self).dispatch(*args, **kwargs)
  46 
  47     def render_to_response(self, context, **response_kwargs):
  48         return HttpSVGResponse(self.get_object().get_elevation_profile_svg(),
  49                                **response_kwargs)
  50 
  51 
  52 class ElevationProfile(LastModifiedMixin, JSONResponseMixin, BaseDetailView):
  53     """Extract elevation profile from a path and return it as JSON"""
  54 
  55     @method_decorator(login_required)
  56     def dispatch(self, *args, **kwargs):
  57         return super(ElevationProfile, self).dispatch(*args, **kwargs)
  58 
  59     def get_context_data(self, **kwargs):
  60         """
  61         Put elevation profile into response context.
  62         """
  63         obj = self.get_object()
  64         data = {}
  65         # Formatted as distance, elevation, [lng, lat]
  66         for step in obj.get_elevation_profile():
  67             formatted = step[0], step[3], step[1:3]
  68             data.setdefault('profile', []).append(formatted)
  69         return data
  70 
  71 
  72 class ElevationArea(LastModifiedMixin, JSONResponseMixin, BaseDetailView):
  73     """Extract elevation profile on an area and return it as JSON"""
  74 
  75     @method_decorator(login_required)
  76     def dispatch(self, *args, **kwargs):
  77         return super(ElevationArea, self).dispatch(*args, **kwargs)
  78 
  79     def get_context_data(self, **kwargs):
  80         obj = self.get_object()
  81         return obj.get_elevation_area()
  82 
  83 
  84 class PathLayer(MapEntityLayer):
  85     model = Path
  86     properties = ['name']
  87 
  88 
  89 class PathList(MapEntityList):
  90     queryset = Path.objects.prefetch_related('networks').select_related('stake', 'trail')
  91     filterform = PathFilter
  92     columns = ['id', 'name', 'networks', 'stake', 'trail']
  93 
  94 
  95 class PathJsonList(MapEntityJsonList, PathList):
  96     pass
  97 
  98 
  99 class PathFormatList(MapEntityFormat, PathList):
  100     pass
  101 
  102 
  103 class PathDetail(MapEntityDetail):
  104     model = Path
  105 
  106     def can_edit(self):
  107         return self.request.user.is_superuser or \
  108                (hasattr(self.request.user, 'profile') and \
  109                 self.request.user.profile.is_path_manager and \
  110                 self.get_object().same_structure(self.request.user))
  111 
  112 
  113 class PathDocument(MapEntityDocument):
  114     model = Path
  115 
  116     def get_context_data(self, *args, **kwargs):
  117         self.get_object().prepare_elevation_chart(self.request)
  118         return super(PathDocument, self).get_context_data(*args, **kwargs)
  119 
  120 
  121 class PathCreate(MapEntityCreate):
  122     model = Path
  123     form_class = PathForm
  124 
  125     @method_decorator(path_manager_required('core:path_list'))
  126     def dispatch(self, *args, **kwargs):
  127         return super(PathCreate, self).dispatch(*args, **kwargs)
  128 
  129 
  130 class PathUpdate(MapEntityUpdate):
  131     model = Path
  132     form_class = PathForm
  133 
  134     @method_decorator(path_manager_required('core:path_detail'))
  135     @same_structure_required('core:path_detail')
  136     def dispatch(self, *args, **kwargs):
  137         return super(PathUpdate, self).dispatch(*args, **kwargs)
  138 
  139 
  140 class PathDelete(MapEntityDelete):
  141     model = Path
  142 
  143     @method_decorator(path_manager_required('core:path_detail'))
  144     @same_structure_required('core:path_detail')
  145     def dispatch(self, *args, **kwargs):
  146         return super(PathDelete, self).dispatch(*args, **kwargs)
  147 
  148 
  149 @login_required
  150 @cache_last_modified(lambda x: Path.latest_updated())
  151 def get_graph_json(request):
  152     cache = get_cache('fat')
  153     key = 'path_graph_json'
  154 
  155     result = cache.get(key)
  156     latest = Path.latest_updated()
  157 
  158     if result and latest:
  159         cache_latest, json_graph = result
  160         # Not empty and still valid
  161         if cache_latest and cache_latest >= latest:
  162             return HttpJSONResponse(json_graph)
  163 
  164     # cache does not exist or is not up to date
  165     # rebuild the graph and cache the json
  166     graph = graph_lib.graph_edges_nodes_of_qs(Path.objects.all())
  167     json_graph = json.dumps(graph)
  168 
  169     cache.set(key, (latest, json_graph))
  170     return HttpJSONResponse(json_graph)
  171 
  172 
  173 class TrailDetail(MapEntityDetail):
  174     model = Trail
  175 
  176     def can_edit(self):
  177         return False
  178 
  179 
  180 class TrailDocument(MapEntityDocument):
  181     model = Trail
  182
  ```
  --- 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/geotrek/core/views.py b/geotrek/core/views.py
  --- a/geotrek/core/views.py
  +++ b/geotrek/core/views.py
  @@ -4,6 +4,7 @@
   from django.utils.decorators import method_decorator
   from django.contrib.auth.decorators import login_required
   from django.views.decorators.http import last_modified as cache_last_modified
  +from django.views.decorators.cache import never_cache as force_cache_validation
   from django.views.generic.edit import BaseDetailView
   from django.core.cache import get_cache
   from django.shortcuts import redirect
  @@ -148,6 +149,7 @@
   
   @login_required
   @cache_last_modified(lambda x: Path.latest_updated())
  +@force_cache_validation
   def get_graph_json(request):
       cache = get_cache('fat')
       key = 'path_graph_json'
  
verification_info: {"golden_diff": "diff --git a/geotrek/core/views.py b/geotrek/core/views.py\n--- a/geotrek/core/views.py\n+++ b/geotrek/core/views.py\n@@ -4,6 +4,7 @@\n from django.utils.decorators import method_decorator\n from django.contrib.auth.decorators import login_required\n from django.views.decorators.http import last_modified as cache_last_modified\n+from django.views.decorators.cache import never_cache as force_cache_validation\n from django.views.generic.edit import BaseDetailView\n from django.core.cache import get_cache\n from django.shortcuts import redirect\n@@ -148,6 +149,7 @@\n \n @login_required\n @cache_last_modified(lambda x: Path.latest_updated())\n+@force_cache_validation\n def get_graph_json(request):\n     cache = get_cache('fat')\n     key = 'path_graph_json'\n", "issue": "Pragma no cache for path graph json\nAs in https://github.com/makinacorpus/django-mapentity/pull/48\n\nRelated https://github.com/makinacorpus/Geotrek/issues/1026\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nimport json\nfrom django.http import HttpResponse\nfrom django.utils.decorators import method_decorator\nfrom django.contrib.auth.decorators import login_required\nfrom django.views.decorators.http import last_modified as cache_last_modified\nfrom django.views.generic.edit import BaseDetailView\nfrom django.core.cache import get_cache\nfrom django.shortcuts import redirect\n\nfrom mapentity.views import (MapEntityLayer, MapEntityList, MapEntityJsonList,\n                             MapEntityDetail, MapEntityDocument, MapEntityCreate, MapEntityUpdate,\n                             MapEntityDelete, MapEntityFormat,\n                             JSONResponseMixin, HttpJSONResponse, LastModifiedMixin)\n\nfrom geotrek.authent.decorators import path_manager_required, same_structure_required\n\nfrom .models import Path, Trail\nfrom .forms import PathForm\nfrom .filters import PathFilter\nfrom . import graph as graph_lib\n\n\n@login_required\ndef last_list(request):\n    last = request.session.get('last_list')  # set in MapEntityList\n    if not last:\n        return redirect('core:path_list')\n    return redirect(last)\n\nhome = last_list\n\n\nclass HttpSVGResponse(HttpResponse):\n    content_type = 'image/svg+xml'\n    def __init__(self, content='', **kwargs):\n        kwargs['content_type'] = self.content_type\n        super(HttpSVGResponse, self).__init__(content, **kwargs)\n\n\nclass ElevationChart(LastModifiedMixin, BaseDetailView):\n\n    @method_decorator(login_required)\n    def dispatch(self, *args, **kwargs):\n        return super(ElevationChart, self).dispatch(*args, **kwargs)\n\n    def render_to_response(self, context, **response_kwargs):\n        return HttpSVGResponse(self.get_object().get_elevation_profile_svg(),\n                               **response_kwargs)\n\n\nclass ElevationProfile(LastModifiedMixin, JSONResponseMixin, BaseDetailView):\n    \"\"\"Extract elevation profile from a path and return it as JSON\"\"\"\n\n    @method_decorator(login_required)\n    def dispatch(self, *args, **kwargs):\n        return super(ElevationProfile, self).dispatch(*args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        \"\"\"\n        Put elevation profile into response context.\n        \"\"\"\n        obj = self.get_object()\n        data = {}\n        # Formatted as distance, elevation, [lng, lat]\n        for step in obj.get_elevation_profile():\n            formatted = step[0], step[3], step[1:3]\n            data.setdefault('profile', []).append(formatted)\n        return data\n\n\nclass ElevationArea(LastModifiedMixin, JSONResponseMixin, BaseDetailView):\n    \"\"\"Extract elevation profile on an area and return it as JSON\"\"\"\n\n    @method_decorator(login_required)\n    def dispatch(self, *args, **kwargs):\n        return super(ElevationArea, self).dispatch(*args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        obj = self.get_object()\n        return obj.get_elevation_area()\n\n\nclass PathLayer(MapEntityLayer):\n    model = Path\n    properties = ['name']\n\n\nclass PathList(MapEntityList):\n    queryset = Path.objects.prefetch_related('networks').select_related('stake', 'trail')\n    filterform = PathFilter\n    columns = ['id', 'name', 'networks', 'stake', 'trail']\n\n\nclass PathJsonList(MapEntityJsonList, PathList):\n    pass\n\n\nclass PathFormatList(MapEntityFormat, PathList):\n    pass\n\n\nclass PathDetail(MapEntityDetail):\n    model = Path\n\n    def can_edit(self):\n        return self.request.user.is_superuser or \\\n               (hasattr(self.request.user, 'profile') and \\\n                self.request.user.profile.is_path_manager and \\\n                self.get_object().same_structure(self.request.user))\n\n\nclass PathDocument(MapEntityDocument):\n    model = Path\n\n    def get_context_data(self, *args, **kwargs):\n        self.get_object().prepare_elevation_chart(self.request)\n        return super(PathDocument, self).get_context_data(*args, **kwargs)\n\n\nclass PathCreate(MapEntityCreate):\n    model = Path\n    form_class = PathForm\n\n    @method_decorator(path_manager_required('core:path_list'))\n    def dispatch(self, *args, **kwargs):\n        return super(PathCreate, self).dispatch(*args, **kwargs)\n\n\nclass PathUpdate(MapEntityUpdate):\n    model = Path\n    form_class = PathForm\n\n    @method_decorator(path_manager_required('core:path_detail'))\n    @same_structure_required('core:path_detail')\n    def dispatch(self, *args, **kwargs):\n        return super(PathUpdate, self).dispatch(*args, **kwargs)\n\n\nclass PathDelete(MapEntityDelete):\n    model = Path\n\n    @method_decorator(path_manager_required('core:path_detail'))\n    @same_structure_required('core:path_detail')\n    def dispatch(self, *args, **kwargs):\n        return super(PathDelete, self).dispatch(*args, **kwargs)\n\n\n@login_required\n@cache_last_modified(lambda x: Path.latest_updated())\ndef get_graph_json(request):\n    cache = get_cache('fat')\n    key = 'path_graph_json'\n\n    result = cache.get(key)\n    latest = Path.latest_updated()\n\n    if result and latest:\n        cache_latest, json_graph = result\n        # Not empty and still valid\n        if cache_latest and cache_latest >= latest:\n            return HttpJSONResponse(json_graph)\n\n    # cache does not exist or is not up to date\n    # rebuild the graph and cache the json\n    graph = graph_lib.graph_edges_nodes_of_qs(Path.objects.all())\n    json_graph = json.dumps(graph)\n\n    cache.set(key, (latest, json_graph))\n    return HttpJSONResponse(json_graph)\n\n\nclass TrailDetail(MapEntityDetail):\n    model = Trail\n\n    def can_edit(self):\n        return False\n\n\nclass TrailDocument(MapEntityDocument):\n    model = Trail\n", "path": "geotrek/core/views.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nimport json\nfrom django.http import HttpResponse\nfrom django.utils.decorators import method_decorator\nfrom django.contrib.auth.decorators import login_required\nfrom django.views.decorators.http import last_modified as cache_last_modified\nfrom django.views.decorators.cache import never_cache as force_cache_validation\nfrom django.views.generic.edit import BaseDetailView\nfrom django.core.cache import get_cache\nfrom django.shortcuts import redirect\n\nfrom mapentity.views import (MapEntityLayer, MapEntityList, MapEntityJsonList,\n                             MapEntityDetail, MapEntityDocument, MapEntityCreate, MapEntityUpdate,\n                             MapEntityDelete, MapEntityFormat,\n                             JSONResponseMixin, HttpJSONResponse, LastModifiedMixin)\n\nfrom geotrek.authent.decorators import path_manager_required, same_structure_required\n\nfrom .models import Path, Trail\nfrom .forms import PathForm\nfrom .filters import PathFilter\nfrom . import graph as graph_lib\n\n\n@login_required\ndef last_list(request):\n    last = request.session.get('last_list')  # set in MapEntityList\n    if not last:\n        return redirect('core:path_list')\n    return redirect(last)\n\nhome = last_list\n\n\nclass HttpSVGResponse(HttpResponse):\n    content_type = 'image/svg+xml'\n    def __init__(self, content='', **kwargs):\n        kwargs['content_type'] = self.content_type\n        super(HttpSVGResponse, self).__init__(content, **kwargs)\n\n\nclass ElevationChart(LastModifiedMixin, BaseDetailView):\n\n    @method_decorator(login_required)\n    def dispatch(self, *args, **kwargs):\n        return super(ElevationChart, self).dispatch(*args, **kwargs)\n\n    def render_to_response(self, context, **response_kwargs):\n        return HttpSVGResponse(self.get_object().get_elevation_profile_svg(),\n                               **response_kwargs)\n\n\nclass ElevationProfile(LastModifiedMixin, JSONResponseMixin, BaseDetailView):\n    \"\"\"Extract elevation profile from a path and return it as JSON\"\"\"\n\n    @method_decorator(login_required)\n    def dispatch(self, *args, **kwargs):\n        return super(ElevationProfile, self).dispatch(*args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        \"\"\"\n        Put elevation profile into response context.\n        \"\"\"\n        obj = self.get_object()\n        data = {}\n        # Formatted as distance, elevation, [lng, lat]\n        for step in obj.get_elevation_profile():\n            formatted = step[0], step[3], step[1:3]\n            data.setdefault('profile', []).append(formatted)\n        return data\n\n\nclass ElevationArea(LastModifiedMixin, JSONResponseMixin, BaseDetailView):\n    \"\"\"Extract elevation profile on an area and return it as JSON\"\"\"\n\n    @method_decorator(login_required)\n    def dispatch(self, *args, **kwargs):\n        return super(ElevationArea, self).dispatch(*args, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        obj = self.get_object()\n        return obj.get_elevation_area()\n\n\nclass PathLayer(MapEntityLayer):\n    model = Path\n    properties = ['name']\n\n\nclass PathList(MapEntityList):\n    queryset = Path.objects.prefetch_related('networks').select_related('stake', 'trail')\n    filterform = PathFilter\n    columns = ['id', 'name', 'networks', 'stake', 'trail']\n\n\nclass PathJsonList(MapEntityJsonList, PathList):\n    pass\n\n\nclass PathFormatList(MapEntityFormat, PathList):\n    pass\n\n\nclass PathDetail(MapEntityDetail):\n    model = Path\n\n    def can_edit(self):\n        return self.request.user.is_superuser or \\\n               (hasattr(self.request.user, 'profile') and \\\n                self.request.user.profile.is_path_manager and \\\n                self.get_object().same_structure(self.request.user))\n\n\nclass PathDocument(MapEntityDocument):\n    model = Path\n\n    def get_context_data(self, *args, **kwargs):\n        self.get_object().prepare_elevation_chart(self.request)\n        return super(PathDocument, self).get_context_data(*args, **kwargs)\n\n\nclass PathCreate(MapEntityCreate):\n    model = Path\n    form_class = PathForm\n\n    @method_decorator(path_manager_required('core:path_list'))\n    def dispatch(self, *args, **kwargs):\n        return super(PathCreate, self).dispatch(*args, **kwargs)\n\n\nclass PathUpdate(MapEntityUpdate):\n    model = Path\n    form_class = PathForm\n\n    @method_decorator(path_manager_required('core:path_detail'))\n    @same_structure_required('core:path_detail')\n    def dispatch(self, *args, **kwargs):\n        return super(PathUpdate, self).dispatch(*args, **kwargs)\n\n\nclass PathDelete(MapEntityDelete):\n    model = Path\n\n    @method_decorator(path_manager_required('core:path_detail'))\n    @same_structure_required('core:path_detail')\n    def dispatch(self, *args, **kwargs):\n        return super(PathDelete, self).dispatch(*args, **kwargs)\n\n\n@login_required\n@cache_last_modified(lambda x: Path.latest_updated())\n@force_cache_validation\ndef get_graph_json(request):\n    cache = get_cache('fat')\n    key = 'path_graph_json'\n\n    result = cache.get(key)\n    latest = Path.latest_updated()\n\n    if result and latest:\n        cache_latest, json_graph = result\n        # Not empty and still valid\n        if cache_latest and cache_latest >= latest:\n            return HttpJSONResponse(json_graph)\n\n    # cache does not exist or is not up to date\n    # rebuild the graph and cache the json\n    graph = graph_lib.graph_edges_nodes_of_qs(Path.objects.all())\n    json_graph = json.dumps(graph)\n\n    cache.set(key, (latest, json_graph))\n    return HttpJSONResponse(json_graph)\n\n\nclass TrailDetail(MapEntityDetail):\n    model = Trail\n\n    def can_edit(self):\n        return False\n\n\nclass TrailDocument(MapEntityDocument):\n    model = Trail\n", "path": "geotrek/core/views.py"}]}