def set_helpers(self, context): """ Called from the ``page_menu`` template tag and assigns a handful of properties based on the current page, that are used within the various types of menus. """ current_page = context["_current_page"] current_page_id = getattr(current_page, "id", None) current_parent_id = getattr(current_page, "parent_id", None) # Am I a child of the current page? self.is_current_child = self.parent_id == current_page_id self.is_child = self.is_current_child # Backward compatibility # Is my parent the same as the current page's? self.is_current_sibling = self.parent_id == current_parent_id # Am I the current page? try: request = context["request"] except KeyError: # No request context, most likely when tests are run. self.is_current = False else: self.is_current = self.slug == path_to_slug(request.path_info) # Is the current page me or any page up the parent chain? def is_c_or_a(page_id): parent_id = context.get("_parent_page_ids", {}).get(page_id) return self.id == page_id or (parent_id and is_c_or_a(parent_id)) self.is_current_or_ascendant = lambda: bool(is_c_or_a(current_page_id)) self.is_current_parent = self.id == current_parent_id # Am I a primary page? self.is_primary = self.parent_id is None # What's an ID I can use in HTML? self.html_id = self.slug.replace("/", "-") # Default branch level - gets assigned in the page_menu tag. self.branch_level = 0
def process_view(self, request, view_func, view_args, view_kwargs): """ Per-request mechanics for the current page object. """ # Load the closest matching page by slug, and assign it to the # request object. If none found, skip all further processing. slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug( slug, for_user=request.user, include_login_required=True) if pages: page = pages[0] setattr(request, "page", page) context_processors.page(request) else: return # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): return redirect_to_login(request.get_full_path()) # If the view isn't Mezzanine's page view, try to return the result # immediately. In the case of a 404 with an URL slug that matches a # page exactly, swallow the exception and try Mezzanine's page view. # # This allows us to set up pages with URLs that also match non-page # urlpatterns. For example, a page could be created with the URL # /blog/about/, which would match the blog urlpattern, and assuming # there wasn't a blog post with the slug "about", would raise a 404 # and subsequently be rendered by Mezzanine's page view. if view_func != page_view: try: return view_func(request, *view_args, **view_kwargs) except Http404: if page.slug != slug: raise # Run page processors. extra_context = {} model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: for k, v in processor_response.items(): if k not in extra_context: extra_context[k] = v except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return page_view(request, slug, extra_context=extra_context)
def set_helpers(self, context): """ Called from the ``page_menu`` template tag and assigns a handful of properties based on the current page, that are used within the various types of menus. """ current_page = context["_current_page"] current_page_id = getattr(current_page, "id", None) current_parent_id = getattr(current_page, "parent_id", None) # Am I a child of the current page? self.is_current_child = self.parent_id == current_page_id self.is_child = self.is_current_child # Backward compatibility # Is my parent the same as the current page's? self.is_current_sibling = self.parent_id == current_parent_id # Am I the current page? try: request = context["request"] except KeyError: # No request context, most likely when tests are run. self.is_current = False else: self.is_current = self.slug == path_to_slug(request.path_info) # Is the current page me or any page up the parent chain? def is_c_or_a(page_id): parent_id = context["_parent_page_ids"].get(page_id) return self.id == page_id or (parent_id and is_c_or_a(parent_id)) self.is_current_or_ascendant = lambda: bool(is_c_or_a(current_page_id)) # Am I a primary page? self.is_primary = self.parent_id is None # What's an ID I can use in HTML? self.html_id = self.slug.replace("/", "-") # Default branch level - gets assigned in the page_menu tag. self.branch_level = 0
def process_view(self, request, view_func, view_args, view_kwargs): """ Per-request mechanics for the current page object. """ # Load the closest matching page by slug, and assign it to the # request object. If none found, skip all further processing. slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug(slug, for_user=request.user, include_login_required=True) if pages: page = pages[0] setattr(request, "page", page) context_processors.page(request) else: return # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): return redirect_to_login(request.get_full_path()) # If the view isn't Mezzanine's page view, try to return the result # immediately. In the case of a 404 with an URL slug that matches a # page exactly, swallow the exception and try Mezzanine's page view. # # This allows us to set up pages with URLs that also match non-page # urlpatterns. For example, a page could be created with the URL # /blog/about/, which would match the blog urlpattern, and assuming # there wasn't a blog post with the slug "about", would raise a 404 # and subsequently be rendered by Mezzanine's page view. if view_func != page_view: try: return view_func(request, *view_args, **view_kwargs) except Http404: if page.slug != slug: raise # Run page processors. extra_context = {} model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: for k, v in processor_response.items(): if k not in extra_context: extra_context[k] = v except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return page_view(request, slug, extra_context=extra_context)
def get_extra_context(self, request): slug = path_to_slug(request.path_info) # Links may have slugs that begin and end in '/' parts = slug.split("/") slugs = ["/".join(parts[:i]) for i in range(1, len(parts) + 1)] slugs = ['/' + i + '/' for i in slugs] + slugs pages = Page.objects.published( for_user=request.user, include_login_required=True ).filter( slug__in=slugs ).order_by( '-slug' ) if pages: page = pages[0] context = { 'page': page, '_current_page': page, } page.set_helpers(context) return context else: return {}
def process_view(self, request, view_func, view_args, view_kwargs): slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug(slug, for_user=request.user, include_login_required=True) if pages: page = pages[0] else: # If we can't find a page matching this slug or any # of its sub-slugs, skip all further processing. return view_func(request, *view_args, **view_kwargs) # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) if page.slug == slug and view_func == page_view: # Add the page to the ``extra_context`` arg for the # page view, which is responsible for choosing which # template to use, and raising 404 if there's no page # instance loaded. view_kwargs.setdefault("extra_context", {}) view_kwargs["extra_context"]["page"] = page # Create the response, and check that we can add context # to it. If not, it's something like a redirect, so we # just return it. response = view_func(request, *view_args, **view_kwargs) if not hasattr(response, "context_data"): return response # Add the page to its template context, and set helper # attributes like ``is_current``. response.context_data["page"] = page response.context_data["_current_page"] = page page.set_helpers(response.context_data) # Run page processors. model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: response.context_data.update(processor_response) except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return response
def process_view(self, request, view_func, view_args, view_kwargs): slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug(slug, request.user) if pages: page = pages[0] else: # If we can't find a page matching this slug or any # of its sub-slugs, skip all further processing. return view_func(request, *view_args, **view_kwargs) # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) if page.slug == slug and view_func == page_view: # Add the page to the ``extra_context`` arg for the # page view, which is responsible for choosing which # template to use, and raising 404 if there's no page # instance loaded. view_kwargs.setdefault("extra_context", {}) view_kwargs["extra_context"]["page"] = page # Create the response, and check that we can add context # to it. If not, it's something like a redirect, so we # just return it. response = view_func(request, *view_args, **view_kwargs) if not hasattr(response, "context_data"): return response # Add the page to its template context, and set helper # attributes like ``is_current``. response.context_data["page"] = page response.context_data["_current_page"] = page page.set_helpers(response.context_data) # Run page processors. model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: response.context_data.update(processor_response) except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return response
def get_extra_context(self, request): slug = path_to_slug(request.path_info) # Links may have slugs that begin and end in '/' parts = slug.split("/") slugs = ["/".join(parts[:i]) for i in range(1, len(parts) + 1)] slugs = ['/' + i + '/' for i in slugs] + slugs pages = Page.objects.published(for_user=request.user, include_login_required=True).filter( slug__in=slugs).order_by('-slug') if pages: page = pages[0] context = { 'page': page, '_current_page': page, } page.set_helpers(context) return context else: return {}
def process_view(self, request, view_func, view_args, view_kwargs): slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug(slug, for_user=request.user, include_login_required=True) if pages: page = pages[0] else: # If we can't find a page matching this slug or any # of its sub-slugs, skip all further processing. return None # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) if page.slug == slug and view_func == page_view: # Add the page to the ``extra_context`` arg for the # page view, which is responsible for choosing which # template to use, and raising 404 if there's no page # instance loaded. view_kwargs.setdefault("extra_context", {}) view_kwargs["extra_context"]["page"] = page # We also first do wacky check with non-page views and 404s. # Basically if the view function isn't the page view and # raises a 404, but also matches an exact page slug, we then # forget about the non-page view, and run the page view # with the correct args. # This check allows us to set up pages with URLs that also # match non-page urlpatterns, for example a page could be # created with the URL /blog/about/, which would match the # blog urlpattern, and asusming there wasn't a blog post # with the slug "about", would raise a 404. try: response = view_func(request, *view_args, **view_kwargs) except Http404: if (page.slug == slug and view_func != page_view and page.content_model != 'link'): # Matched a non-page urlpattern, but got a 404 # for a URL that matches a valid page slug, so # use the page view. view_kwargs = { "extra_context": {"page": page} } view_func = page_view response = view_func(request, slug, **view_kwargs) else: raise # If we can't add context to the response we just return it. # (redirects, etc) if getattr(response, "context_data", None) is None: return response # Add the page to its template context, and set helper # attributes like ``is_current``. response.context_data["page"] = page try: response.context_data["editable_obj"] except KeyError: response.context_data["editable_obj"] = page response.context_data["_current_page"] = page page.set_helpers(response.context_data) # Run page processors. model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: for k in processor_response: if k not in response.context_data: response.context_data[k] = processor_response[k] except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return response
def process_view(self, request, view_func, view_args, view_kwargs): """ Per-request mechanics for the current page object. """ cp = "mezzanine.pages.context_processors.page" if cp not in settings.TEMPLATE_CONTEXT_PROCESSORS: raise ImproperlyConfigured("%s is missing from " "settings.TEMPLATE_CONTEXT_PROCESSORS" % cp) # Load the closest matching page by slug, and assign it to the # request object. If none found, skip all further processing. slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug(slug, for_user=request.user, include_login_required=True) if pages: page = pages[0] setattr(request, "page", page) else: return # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) # Here we do a wacky check with non-page views and 404s. # Basically if the view function isn't the page view and # raises a 404, but also matches an exact page slug, we then # forget about the non-page view, and run the page view # with the correct args. # This check allows us to set up pages with URLs that also # match non-page urlpatterns, for example a page could be # created with the URL /blog/about/, which would match the # blog urlpattern, and assuming there wasn't a blog post # with the slug "about", would raise a 404. try: response = view_func(request, *view_args, **view_kwargs) except Http404: if (page.slug == slug and view_func != page_view and page.content_model != 'link'): # Matched a non-page urlpattern, but got a 404 # for a URL that matches a valid page slug, so # use the page view. response = page_view(request, slug, **view_kwargs) else: raise # Run page processors. model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: for k in processor_response: if k not in response.context_data: response.context_data[k] = processor_response[k] except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return response
def process_view(self, request, view_func, view_args, view_kwargs): """ Per-request mechanics for the current page object. """ cp = "mezzanine.pages.context_processors.page" if cp not in settings.TEMPLATE_CONTEXT_PROCESSORS: raise ImproperlyConfigured("%s is missing from " "settings.TEMPLATE_CONTEXT_PROCESSORS" % cp) # Load the closest matching page by slug, and assign it to the # request object. If none found, skip all further processing. slug = path_to_slug(request.path_info) pages = Page.objects.with_ascendants_for_slug( slug, for_user=request.user, include_login_required=True) if pages: page = pages[0] setattr(request, "page", page) else: return # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) # Here we do a wacky check with non-page views and 404s. # Basically if the view function isn't the page view and # raises a 404, but also matches an exact page slug, we then # forget about the non-page view, and run the page view # with the correct args. # This check allows us to set up pages with URLs that also # match non-page urlpatterns, for example a page could be # created with the URL /blog/about/, which would match the # blog urlpattern, and assuming there wasn't a blog post # with the slug "about", would raise a 404. try: response = view_func(request, *view_args, **view_kwargs) except Http404: if (page.slug == slug and view_func != page_view and page.content_model != 'link'): # Matched a non-page urlpattern, but got a 404 # for a URL that matches a valid page slug, so # use the page view. response = page_view(request, slug, **view_kwargs) else: raise # Run page processors. model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in slug_processors + model_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response and hasattr(response, "context_data"): try: for k in processor_response: if k not in response.context_data: response.context_data[k] = processor_response[k] except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return response
def process_view(self, request, view_func, view_args, view_kwargs): slug = path_to_slug(request.path_info) if slug == "/": slugs = [slug] else: # Create a list containing this slug, plus each of the # ascendant slugs: ['about', 'about/team', 'about/team/mike'] parts = slug.split("/") slugs = ["/".join(parts[:i]) for i in range(1, len(parts) + 1)] pages_for_user = Page.objects.published(request.user) try: # Find the deepest page that matches one of our slugs. # Sorting by "-slug" ensures that the page with the # longest slug is selected if more than one page matches. page = pages_for_user.filter(slug__in=slugs).order_by("-slug")[0] except IndexError: # If we can't find a page matching this slug or any # of its sub-slugs, skip all further processing. return view_func(request, *view_args, **view_kwargs) # Handle ``page.login_required``. if page.login_required and not request.user.is_authenticated(): path = urlquote(request.get_full_path()) bits = (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path) return redirect("%s?%s=%s" % bits) if page.slug == slug and view_func == page_view: # Add the page to the ``extra_context`` arg for the # page view, which is responsible for choosing which # template to use, and raising 404 if there's no page # instance loaded. view_kwargs.setdefault("extra_context", {}) view_kwargs["extra_context"]["page"] = page # Create the response, and check that we can add context # to it. If not, it's something like a redirect, so we # just return it. response = view_func(request, *view_args, **view_kwargs) if not hasattr(response, "context_data"): return response # Add the page to its template context, and set helper # attributes like ``is_current``. response.context_data["page"] = page response.context_data["_current_page"] = page page.set_helpers(response.context_data) # Run page processors. model_processors = page_processors.processors[page.content_model] slug_processors = page_processors.processors["slug:%s" % page.slug] for (processor, exact_page) in model_processors + slug_processors: if exact_page and not page.is_current: continue processor_response = processor(request, page) if isinstance(processor_response, HttpResponse): return processor_response elif processor_response: try: response.context_data.update(processor_response) except (TypeError, ValueError): name = "%s.%s" % (processor.__module__, processor.__name__) error = ("The page processor %s returned %s but must " "return HttpResponse or dict." % (name, type(processor_response))) raise ValueError(error) return response
def get_page(request): check_if_middleware_exists("mezzanine.pages") slug = path_to_slug(request.path_info) pages = page_service.get_page_ascendants(request, slug) return reduce(default_or_value, pages, "")