88from cms .models import Page , PageContent , Placeholder
99from cms .utils .conf import get_languages
1010from cms .utils .page_permissions import user_can_view_page
11+ from menus .menu_pool import menu_pool
1112from menus .templatetags .menu_tags import ShowBreadcrumb , ShowMenu , ShowSubMenu
1213
1314
@@ -90,9 +91,7 @@ def extend_placeholder_schema(func: Callable[P, T]) -> Callable[P, T]:
9091# Attn: Dynamic changes to the plugin pool will not be reflected in the
9192# plugin definitions.
9293# If you need to update the plugin definitions, you need to reassign the variable.
93- PLUGIN_DEFINITIONS = lazy (
94- PluginDefinitionSerializer .generate_plugin_definitions , dict
95- )()
94+ PLUGIN_DEFINITIONS = lazy (PluginDefinitionSerializer .generate_plugin_definitions , dict )()
9695
9796
9897class LanguageListView (BaseAPIView ):
@@ -161,9 +160,7 @@ def get(self, request, language):
161160 except PageContent .DoesNotExist :
162161 raise NotFound ()
163162
164- serializer = self .serializer_class (
165- pages , many = True , read_only = True , context = {"request" : request }
166- )
163+ serializer = self .serializer_class (pages , many = True , read_only = True , context = {"request" : request })
167164 return Response (serializer .data )
168165
169166
@@ -182,9 +179,7 @@ def get(self, request: Request, language: str, path: str = "") -> Response:
182179 page_content = getattr (page , self .content_getter )(language , fallback = True )
183180 if page_content is None :
184181 raise PageContent .DoesNotExist ()
185- serializer = self .serializer_class (
186- page_content , read_only = True , context = {"request" : request }
187- )
182+ serializer = self .serializer_class (page_content , read_only = True , context = {"request" : request })
188183 return Response (serializer .data )
189184 except PageContent .DoesNotExist :
190185 raise NotFound ()
@@ -216,19 +211,13 @@ def get(
216211 - "html": The content rendered as html. Sekizai blocks such as "js" or "css" will be added
217212 as separate attributes"""
218213 try :
219- placeholder = Placeholder .objects .get (
220- content_type_id = content_type_id , object_id = object_id , slot = slot
221- )
214+ placeholder = Placeholder .objects .get (content_type_id = content_type_id , object_id = object_id , slot = slot )
222215 except Placeholder .DoesNotExist :
223216 raise NotFound ()
224217
225218 source_model = placeholder .content_type .model_class ()
226219 content_manager = "admin_manager" if self ._preview_requested () else "content"
227- source = (
228- getattr (source_model , content_manager , source_model .objects )
229- .filter (pk = placeholder .object_id )
230- .first ()
231- )
220+ source = getattr (source_model , content_manager , source_model .objects ).filter (pk = placeholder .object_id ).first ()
232221
233222 if source is None :
234223 raise NotFound ()
@@ -242,9 +231,7 @@ def get(
242231
243232 self .check_object_permissions (request , placeholder )
244233
245- serializer = self .serializer_class (
246- instance = placeholder , request = request , language = language , read_only = True
247- )
234+ serializer = self .serializer_class (instance = placeholder , request = request , language = language , read_only = True )
248235 return Response (serializer .data )
249236
250237
@@ -278,9 +265,7 @@ def method_schema_decorator(method):
278265 Decorator for adding OpenAPI schema to a method.
279266 Needed to force the schema to use many=True for NavigationNodeSerializer.
280267 """
281- return extend_schema (
282- responses = OpenApiResponse (response = NavigationNodeSerializer (many = True ))
283- )(method )
268+ return extend_schema (responses = OpenApiResponse (response = NavigationNodeSerializer (many = True )))(method )
284269
285270except ImportError : # pragma: no cover
286271
@@ -306,9 +291,7 @@ def get(
306291 """Get the menu structure for a specific language and path."""
307292 self .populate_defaults (kwargs )
308293 menu = self .get_menu_structure (request , language , path , ** kwargs )
309- serializer = self .serializer_class (
310- menu , many = True , context = {"request" : request }
311- )
294+ serializer = self .serializer_class (menu , many = True , context = {"request" : request })
312295 return Response (serializer .data )
313296
314297 def populate_defaults (self , kwargs : dict [str , Any ]) -> None :
@@ -341,22 +324,31 @@ def get_menu_structure(
341324 if path == "" :
342325 api_endpoint = reverse ("page-root" , kwargs = {"language" : language })
343326 else :
344- api_endpoint = reverse (
345- "page-detail" , kwargs = {"language" : language , "path" : path }
346- )
327+ api_endpoint = reverse ("page-detail" , kwargs = {"language" : language , "path" : path })
347328
348329 request .api_endpoint = api_endpoint
349330 request .LANGUAGE_CODE = language
350331 request .current_page = get_object (self .site , path )
351332 self .check_object_permissions (request , request .current_page )
352- context = {"request" : request }
333+ menu_renderer = menu_pool .get_renderer (request )
334+ menu_renderer .site = self .site
335+ context = {"request" : request , "cms_menu_renderer" : menu_renderer }
353336
354337 context = tag_instance .get_context (
355338 context = context ,
356339 ** kwargs ,
357340 template = None ,
358341 )
359- return context .get (self .return_key , [])
342+ result = context .get (self .return_key , [])
343+ if not result and kwargs .get ("root_id" ):
344+ # Edge case: No menu nodes found but a root_id was specified.
345+ # This might be due to a non-existing root_id.
346+ nodes = menu_renderer .get_nodes (kwargs .get ("namespace" ), kwargs ["root_id" ])
347+ id_nodes = menu_pool .get_nodes_by_attribute (nodes , "reverse_id" , kwargs ["root_id" ])
348+ if not id_nodes :
349+ raise NotFound ()
350+
351+ return result
360352
361353
362354class SubMenuView (MenuView ):
0 commit comments