Root middleware for pages (feincms3.root)¶
Page middleware (feincms3.root.middleware)¶
The guide recommends using a middleware for the feincms3 pages app. This module
offers helpers and utilities to reduce the amount of code you have to write.
The reason why this module is called root is that the page app’s mountpoint
has to be the Python app’s mountpoint when using this since the middleware uses
the value of request.path_info to find a page for the current request.
If you have other requirements you may want to write your own
URLs and views or investigate if modifying request.path_info works;
the latter isn’t recommended though since it’s not officially supported by
Django.
Example code for using this module (e.g. app.pages.middleware):
from django.shortcuts import render
from feincms3.root.middleware import add_redirect_handler, create_page_if_404_middleware
from app.pages.models import Page
from app.pages.utils import page_context
# The page handler receives the request and the page.
# ``add_redirect_handler`` wraps the handler function with support for the
# RedirectMixin.
@add_redirect_handler
def handler(request, page):
return render(request, page.type.template_name, page_context(request, page=page))
# This is the middleware which you want to add to ``MIDDLEWARE`` as
# ``app.pages.middleware.page_if_404_middleware``. The middleware should be
# added in the last position except if you have a very good reason not to
# do this.
page_if_404_middleware = create_page_if_404_middleware(
# queryset=Page.objects.active() works too (if .active() doesn't use
# get_language or anything similar)
queryset=lambda request: Page.objects.active(),
handler=handler,
)
Building a preview functionality¶
If you wish that staff users can view a page which isn’t active yet, here’s how
to do that. It’s basically the same as above except for the fact that the
queryset function depends on the value of request.user.is_staff.
If you’re using feincms3 applications, it may happen that you want to preview
an application site. This doesn’t work without overriding the list of apps
passed to apps_urlconf(). The easier way to check
if the preview should be rendered is to use the fact that most feincms3
application page types won’t have template_name set. Returning a 404 error
in this case is a good alternative to crashing with an IsADirectoryError
because the Django templates backend tries to load the templates directory
itself instead of a template file.
def pages(request):
if request.user.is_staff:
return Page.objects.all()
return Page.objects.active()
@add_redirect_handler
def handler(request, page):
if not page.type.template_name:
raise Http404(
f"The page type {page.type.key!r} doesn't have a template name."
)
return render(
request,
page.type.template_name,
page_context(request, page=page),
)
page_if_404_middleware = create_page_if_404_middleware(
queryset=pages,
handler=handler,
)
- class feincms3.root.middleware.UseRootMiddlewareResponse(content=b'', *args, **kwargs)[source]¶
Used by feincms3.root.passthru to tell the middleware to do its thing
You can return this response from your own views as well if some view cannot handle a request and you want to allow the root middleware to try handling the current request. If you just raise
Http404or return a stockHttpResponseNotFoundresponse the root middleware will do nothing.As an example, of
get_object_or_404(Thing, pk=pk)you could do the following if you want to fall back to the root middleware:from feincms3.root.middleware import UseRootMiddlewareResponse def view(request, pk): if thing := Thing.objects.filter(pk=pk).first(): return render(...) return UseRootMiddlewareResponse()
This makes the root middleware check the pages for a match, and still return the 404 if no page could be found.
- feincms3.root.middleware.add_redirect_handler(handler)[source]¶
Wrap the page handler in a redirect mixin handler
- feincms3.root.middleware.create_page_if_404_middleware(*, queryset, handler, language_code_redirect=False)[source]¶
Create a middleware for handling pages
This utility is there for your convenience, you do not have to use it. The returned middleware already handles returning non-404 responses as-is, fetching a page instance from the database and calling a user-defined handler on success. It optionally also supports redirecting requests to the root of the app to a language-specific landing page.
Required arguments:
queryset: A page queryset or a callable accepting the request and returning a page queryset.handler: A callable accepting the request and a page and returning a response.
Optional arguments:
language_code_redirect(False): Redirect visitor to the language code prefix (e.g./en/,/de-ch/) if request path equals the script prefix (generally/), no active page for/exists and the prefixed version exists.
Passthru page apps (feincms3.root.passthru)¶
The idea of this module is to allow tagging pages to allow programmatically determing the URL of pages which are often linked to, e.g. privacy policy or imprint pages.
Create an application type:
TYPES = [
...
ApplicationType(
key="imprint",
title=_("imprint"),
urlconf="feincms3.root.passthru",
template_name="pages/standard.html",
regions=[Region(key="main", title=_("Main"))],
),
]
Reverse the URL of the page (if it exists):
# Raise NoReverseMatch on failure
reverse_passthru("imprint")
# Fallback
reverse_passthru("imprint", fallback="/en/imprint/")
# Outside the request-response cycle
reverse_passthru("imprint", urlconf=apps_urlconf())