La aplicación flatpages

Django viene con una aplicación opcional llamada «flatpages». Te permite almacenar contenido HTML plano en una base de datos y manejarlo a través del interfaz administrativo de Django y una API de Python.

Una página plana es un objeto con una URL, título y contenido. Utilízala para páginas uno-a-uno, casos especiales, como las páginas «Acerca de» o «Política de privacidad», que deseas almacenar en una base de datos pero para las cuales no quieres desarrollar una aplicación Django personalizada.

Una página plana puede utilizar un template personalizado o uno predeterminado y sistema. Puede estar asociada con uno, o varios, sitios.

El contenido del campo puede quedar en blanco si prefieres poner tu contenido en un plantilla personalizada.

Instalación

Para instalar la aplicación de páginas planas, sigue estos pasos:

  1. Instala el framework de sitios agregando 'django.contrib.sites' a tu configuración INSTALLED_APPS, si no está ya allí.

    Asegúrate también de haber establecido correctamente SITE_ID con la ID del sitio que representa el archivo de configuración. Normalmente será 1 (es decir, SITE_ID = 1), pero si estás utilizando el framework de sitios para gestionar múltiples sitios, podría ser la ID de un sitio diferente.

  2. Agrega 'django.contrib.flatpages' a tu configuración INSTALLED_APPS.

Luego, ya sea:

  1. Agrega una entrada en tu URLconf. Por ejemplo:

    urlpatterns = [
        path("pages/", include("django.contrib.flatpages.urls")),
    ]
    

o:

  1. Agrega 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' a tu configuración MIDDLEWARE.

  2. Ejecuta el comando: djadmin:`manage.py migrate `<migrate>.

Cómo funciona

manage.py migrate crea dos tablas en tu base de datos: django_flatpage y django_flatpage_sites. django_flatpage es una tabla de búsqueda que mapea una URL a un título y contenido de texto. django_flatpage_sites asocia una página plana con un sitio.

Uso del URLconf

Hay varias formas de incluir las páginas planas en tu URLconf. Puedes dedicar un camino particular a las páginas planas:

urlpatterns = [
    path("pages/", include("django.contrib.flatpages.urls")),
]

También puedes configurarlo como un patrón «catchall». En este caso, es importante colocar el patrón al final de los otros urlpatterns:

from django.contrib.flatpages import views

# Your other patterns here
urlpatterns += [
    re_path(r"^(?P<url>.*/)$", views.flatpage),
]

Advertencia

Si estableces APPEND_SLASH en False, debes eliminar la barra en el patrón catchall o las páginas planas sin una barra final no se coincidirán.

Otra configuración común es utilizar páginas planas para un conjunto limitado de páginas conocidas y codificar sus URLs en el URLconf:

from django.contrib.flatpages import views

urlpatterns += [
    path("about-us/", views.flatpage, kwargs={"url": "/about-us/"}, name="about"),
    path("license/", views.flatpage, kwargs={"url": "/license/"}, name="license"),
]

El argumento kwargs establece el valor url utilizado para la búsqueda del modelo FlatPage en la vista de página plana.

El argumento name permite que la URL se invierta en plantillas, por ejemplo utilizando el url etiqueta de plantilla.

Usando el middleware

El FlatpageFallbackMiddleware puede hacer todo el trabajo.

class FlatpageFallbackMiddleware[fuente]

Cada vez que cualquier aplicación Django levanta un error 404, este middleware verifica la base de datos de flatpages para la URL solicitada como último recurso. Específicamente, verifica una página plana con la URL dada y un ID de sitio que corresponde a la configuración SITE_ID.

Si encuentra una coincidencia, sigue este algoritmo:

  • Si la página plana tiene un template personalizado, carga ese template. De lo contrario, carga el template flatpages/default.html.

  • Pasa a ese template una variable de contexto única, flatpage, que es el objeto de página plana. Utiliza RequestContext al renderizar el template.

El middleware solo agrega un slash final y redirige (mirando la configuración APPEND_SLASH) si la URL resultante se refiere a una página plana válida. Las redirecciones son permanentes (código de estado 301).

Si no encuentra una coincidencia, la solicitud continúa siendo procesada como de costumbre.

El middleware solo se activa para errores 404 – no para errores 500 ni respuestas de ningún otro código de estado.

Las páginas planas no aplicarán middleware de vistas

Porque el FlatpageFallbackMiddleware se aplica solo después de que la resolución de URL ha fallado y producido un 404, la respuesta que devuelve no aplicará métodos del view middleware. Solo las solicitudes que son correctamente dirigidas a una vista mediante la resolución normal de URLs aplican middleware de vistas.

Ten en cuenta que el orden de MIDDLEWARE importa. Generalmente, puedes poner FlatpageFallbackMiddleware al final de la lista. Esto significa que se ejecutará primero cuando se procese la respuesta, y asegura que cualquier otro middleware de procesamiento de respuestas vea la respuesta real de flatpage en lugar del 404.

Para más información sobre middleware, lee los docs de middleware.

Asegúrate de que tu plantilla de 404 funcione

Ten en cuenta que el FlatpageFallbackMiddleware solo interviene una vez que otra vista ha producido con éxito un respuesta de 404. Si otra vista o clase de middleware intenta producir un 404 pero termina elevando una excepción en su lugar, la respuesta se convertirá en un HTTP 500 («Error del servidor») y el FlatpageFallbackMiddleware no intentará servir una página plana.

Cómo agregar, cambiar y eliminar páginas planas

Advertencia

Las permisos para agregar o editar páginas planas deben estar restringidos a usuarios confiables. Las páginas planas se definen mediante HTML crudo y no son sanitizadas por Django. Como consecuencia, una página plana maliciosa puede provocar diversas vulnerabilidades de seguridad, incluyendo la escalada de permisos.

A través de la interfaz administrativa

Si has activado la interfaz administrativa automática de Django, deberías ver una sección «Páginas planas» en la página de inicio del administrador. Edita las páginas planas como editarías cualquier otro objeto en el sistema.

El modelo FlatPage tiene un campo enable_comments que no es utilizado por contrib.flatpages, pero podría ser útil para tu proyecto o aplicaciones terceras. No aparece en la interfaz administrativa, pero puedes agregarlo registrando una ModelAdmin personalizada para FlatPage:

from django.contrib import admin
from django.contrib.flatpages.admin import FlatPageAdmin
from django.contrib.flatpages.models import FlatPage
from django.utils.translation import gettext_lazy as _


# Define a new FlatPageAdmin
class FlatPageAdmin(FlatPageAdmin):
    fieldsets = [
        (None, {"fields": ["url", "title", "content", "sites"]}),
        (
            _("Advanced options"),
            {
                "classes": ["collapse"],
                "fields": [
                    "enable_comments",
                    "registration_required",
                    "template_name",
                ],
            },
        ),
    ]


# Re-register FlatPageAdmin
admin.site.unregister(FlatPage)
admin.site.register(FlatPage, FlatPageAdmin)

A través de la API de Python

Las páginas planas están representadas por un modelo estándar Django: FlatPage. Puedes acceder a objetos de páginas planas mediante la API de base de datos de Django.

Verifica las URL duplicadas de páginas planas.

Si agregas o modificas las páginas planas mediante tu propio código, es probable que desees comprobar la existencia de URLs duplicadas de páginas planas dentro del mismo sitio. La forma de página plana utilizada en la administración realiza esta comprobación de validación y puede importarse desde django.contrib.flatpages.forms.FlatpageForm y usarse en tus propias vistas.

Modelo FlatPage

class models.FlatPage

Campos

Los objetos FlatPage tienen los siguientes campos:

class models.FlatPage
url

Requerido. Menos de 100 caracteres. Índice para consultas más rápidas.

title

Requerido. Menos de 200 caracteres.

content

Opcional (blank=True). TextField que típicamente contiene el contenido en formato HTML de la página.

enable_comments

Boolean. Este campo no se utiliza por defecto por flatpages y no aparece en la interfaz de administración. Consulta la sección de interfaz de administración de flatpages <flatpages-admin> para una explicación detallada.

template_name

Optional (blank=True). 70 caracteres o menos. Especifica el template utilizado para renderizar la página. Por defecto, utiliza flatpages/default.html si no se proporciona.

sites

Relación muchos a muchos con Site, que determina los sitios en los que está disponible la flatpage.

Métodos

class models.FlatPage
get_absolute_url()

Devuelve el camino URL relativo de la página basado en el atributo url.

Plantillas de flatpage

Por defecto, las flatpages se renderizan a través del template flatpages/default.html, pero puedes sobrescribirlo para una flatpage en particular: en la administración, un conjunto de campos titulado «Opciones avanzadas» (haciendo clic en él lo expandirá) contiene un campo para especificar el nombre de la plantilla. Si estás creando una página plana a través de la API de Python puedes establecer el nombre de la plantilla como el campo template_name en el objeto FlatPage.

La creación del template flatpages/default.html es tu responsabilidad; en tu directorio de plantillas, crea un directorio flatpages que contenga un archivo default.html.

Las plantillas de flatpage se pasan una variable de contexto única, flatpage, que es el objeto de la página plana.

Here’s a sample flatpages/default.html template:

<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

Dado que ya estás ingresando HTML crudo en la página de administración para una flatpage, tanto flatpage.title como flatpage.content están marcados como no requiriendo escape de HTML automático en el template.

Obteniendo una lista de objetos FlatPage en tus plantillas

La aplicación de flatpages proporciona una etiqueta de plantilla que te permite iterar sobre todas las páginas disponibles en el sitio actual: <hooking-into-current-site-from-views>.

Al igual que todas las etiquetas de plantillas personalizadas, necesitarás cargar la biblioteca de etiquetas personalizadas antes de poder utilizarla. Una vez cargada la biblioteca, puedes recuperar todas las páginas actuales mediante la etiqueta get_flatpages:

{% load flatpages %}
{% get_flatpages as flatpages %}
<ul>
    {% for page in flatpages %}
        <li><a href="{{ page.url }}">{{ page.title }}</a></li>
    {% endfor %}
</ul>

Mostrando páginas registration_required

Por defecto, la etiqueta de plantilla get_flatpages solo mostrará páginas que tengan marcada registration_required = False. Si deseas mostrar páginas protegidas por registro, necesitarás especificar un usuario autenticado mediante una cláusula for.

Ejemplo:

{% get_flatpages for someuser as about_pages %}

Si proporcionas un usuario anónimo, get_flatpages se comportará de la misma manera que si no hubieras proporcionado un usuario – es decir, solo mostrará páginas públicas.

Limitar páginas por URL base

Un argumento opcional, starts_with, puede aplicarse para limitar las páginas devueltas a aquellas que comiencen con una particular URL base. Este argumento se puede pasar como cadena o como variable a resolver del contexto.

Ejemplo:

{% get_flatpages '/about/' as about_pages %}
{% get_flatpages about_prefix as about_pages %}
{% get_flatpages '/about/' for someuser as about_pages %}

Integración con django.contrib.sitemaps

class FlatPageSitemap[fuente]

La clase sitemaps.FlatPageSitemap analiza todas las páginas públicamente visibles definidas para el sitio actual (ver la documentación de sitios: sites documentation) y crea una entrada en el mapa del sitio. Estas entradas incluyen solo el atributo location – no los atributos lastmod, changefreq o priority.

Ejemplo

Aquí tienes un ejemplo de una configuración de URLs utilizando FlatPageSitemap.

from django.contrib.flatpages.sitemaps import FlatPageSitemap
from django.contrib.sitemaps.views import sitemap
from django.urls import path

urlpatterns = [
    # ...
    # the sitemap
    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": {"flatpages": FlatPageSitemap}},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]