Dispatcher de URL

Un esquema de URL limpio y elegante es un detalle importante en una aplicación web de alta calidad. Django te permite diseñar URLs como desees, sin limitaciones del marco.

Consulte Las URIs fáciles no cambian, por el creador de la World Wide Web Tim Berners-Lee, para argumentos excelentes sobre por qué las URL deben ser limpias y utilizables.

Resumen

Para diseñar URLs para una aplicación, creas un módulo de Python informalmente llamado URLconf (configuración de URL). Este módulo es código Python puro y es una asignación entre expresiones de ruta de URL a funciones de Python (tus vistas).

Esta mapeación puede ser tan corta o larga como sea necesario. Puede hacer referencia a otras mapeaciones. Y, porque es código Python puro, se puede construir dinámicamente.

Django también proporciona una forma de traducir URLs según el idioma activo. Consulte la documentación de internacionalización <url-internationalization> para obtener más información.

Cómo procesa Django una solicitud

Cuando un usuario solicita una página desde su sitio web impulsado por Django, este es el algoritmo que sigue el sistema para determinar qué código Python ejecutar:

  1. Django determina el módulo de configuración raíz URL a utilizar. Ordinariamente, esto es el valor de la configuración ROOT_URLCONF, pero si el objeto HttpRequest entrante tiene un atributo urlconf (establecido por middleware), su valor se usará en lugar de la configuración ROOT_URLCONF.

  2. Django carga ese módulo Python y busca la variable urlpatterns. Esto debería ser una secuencia de instancias de django.urls.path() y/o django.urls.re_path().

  3. Django pasa por cada patrón URL, en orden, y detiene en el primero que coincida con la URL solicitada, coincidiendo contra path_info.

  4. Una vez que se ha encontrado uno de los patrones URL, Django importa y llama al correspondiente vista, que es una función Python (o una vista basada en clase). La vista recibe las siguientes argumentos:

    • Una instancia de HttpRequest.

    • Si el patrón URL coincidente no contenía grupos nombrados, entonces se proporcionan los matches del patrón regular como argumentos posicionales.

    • Los textos traducidos son:

  5. Si no hay un patrón de URL que coincida, o si se levanta una excepción durante algún punto de este proceso, Django invoca una vista de manejo de errores adecuada. Consulte Manejo de errores a continuación.

Ejemplo

Aquí tienes un ejemplo de archivo urlconf:

from django.urls import path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<int:year>/", views.year_archive),
    path("articles/<int:year>/<int:month>/", views.month_archive),
    path("articles/<int:year>/<int:month>/<slug:slug>/", views.article_detail),
]

Notas:

  • Para capturar un valor desde la URL, utiliza signos de angle brackets.

  • Los valores capturados pueden incluir opcionalmente un tipo de conversor. Por ejemplo, utiliza <int:name> para capturar un parámetro entero. Si no se incluye un conversor, cualquier cadena, excluyendo el carácter /, se coincide.

  • No es necesario agregar una barra diagonal delante, porque cada URL tiene eso. Por ejemplo, es articles, no /articles.

Peticiones de ejemplo:

  • Una solicitud a /articles/2005/03/ coincidiría con la tercera entrada en la lista. Django llamaría a la función views.month_archive(request, year=2005, month=3).

  • /articles/2003/ coincidiría con el primer patrón de la lista, no con el segundo, porque los patrones se prueban en orden y el primero es la primera prueba que pasa. Siente libre a aprovechar el orden para insertar casos especiales como este. Aquí, Django llamaría a la función views.special_case_2003(request)

  • /articles/2003 no coincidiría con ninguno de estos patrones, porque cada patrón requiere que la URL termine con una barra diagonal.

  • /articles/2003/03/building-a-django-site/ coincidiría con el patrón final. Django llamaría a la función views.article_detail(request, year=2003, month=3, slug="building-a-django-site").

Convertidores de ruta

Los siguientes convertidores de ruta están disponibles por defecto:

  • str - Coincide con cualquier cadena no vacía, excluyendo el separador de ruta, '/'. Este es el valor predeterminado si no se incluye un conversor en la expresión.

  • int - Coincide con cero o cualquier entero positivo. Devuelve un int.

  • slug - Coincide con cualquier cadena de slug compuesta por letras y números ASCII, más los caracteres de guion y subrayado. Por ejemplo, building-your-1st-django-site.

  • uuid - Coincide con una UUID formateada. Para evitar que múltiples URLs se mapeen a la misma página, deben incluirse las barras y los caracteres de letra deben estar en minúsculas. Por ejemplo, 075194d3-6885-417e-a8a8-6c931e272f00. Devuelve una instancia de UUID.

  • path - Coincide con cualquier cadena no vacía, incluyendo el separador de ruta, '/'. Esto permite coincidir contra un camino de URL completo en lugar de un segmento del camino de URL como con str.

Registro de convertidores de ruta personalizados

Para requisitos de coincidencia más complejos, puedes definir tus propios convertidores de ruta.

Los textos traducidos son:

  • Una atributo de clase regex, como cadena.

  • Un método to_python(self, value), que maneja la conversión de la cadena coincidente al tipo que debe ser pasado a la función del vista. Debe levantar ValueError si no puede convertir el valor dado. Un ValueError se interpreta como sin coincidencia y como consecuencia se envía una respuesta 404 al usuario a menos que otro patrón de URL coincida.

  • Un método to_url(self, value), que maneja la conversión del tipo Python en cadena para ser utilizada en la URL. Debe levantar ValueError si no puede convertir el valor dado. Un ValueError se interpreta como sin coincidencia y como consecuencia reverse() levantará NoReverseMatch a menos que otro patrón de URL coincida.

Por ejemplo:

class FourDigitYearConverter:
    regex = "[0-9]{4}"

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return "%04d" % value

Registra clases de conversores personalizadas en tu URLconf utilizando register_converter():

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, "yyyy")

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<yyyy:year>/", views.year_archive),
    ...,
]

Obsoleto desde la versión 5.1: Sobrescribir conversores existentes con django.urls.register_converter() está descontinuado.

Usando expresiones regulares

Si la sintaxis de los caminos y los conversores no es suficiente para definir tus patrones de URL, también puedes utilizar expresiones regulares. Para ello, utiliza re_path() en lugar de path().

En las expresiones regulares de Python, la sintaxis para grupos de expresión regular nombrados es (?P<name>pattern), donde name es el nombre del grupo y pattern es algún patrón para coincidir.

Aquí tienes el ejemplo URLconf anterior, reescrito utilizando expresiones regulares:

from django.urls import path, re_path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
    re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
    re_path(
        r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$",
        views.article_detail,
    ),
]

Este logra aproximadamente lo mismo que el ejemplo anterior, excepto:

  • Las URL exactas que coincidirán están ligeramente más restringidas. Por ejemplo, el año 10000 ya no coincidirá porque los números enteros de año se ven restringidos a ser exactamente cuatro dígitos de largo.

  • Cada argumento capturado se envía a la vista como una cadena, independientemente de qué tipo de coincidencia hace la expresión regular.

Cuando cambiar de usar path() a re_path() o viceversa, es particularmente importante estar consciente de que el tipo de los argumentos de la vista puede cambiar, y por lo tanto puedes necesitar adaptar tus vistas.

Usando grupos de expresiones regulares sin nombre

Además de la sintaxis del grupo nombrado, por ejemplo (?P<year>[0-9]{4}), también puedes utilizar el grupo no nombrado más corto, por ejemplo ([0-9]{4}).

Este uso no se recomienda particularmente, ya que facilita la introducción de errores entre el significado pretendido de una coincidencia y los argumentos de la vista.

En cualquier caso, se recomienda utilizar solo un estilo dentro de una expresión regular dada. Cuando se mezclan ambos estilos, los grupos sin nombre se ignoran y solo se pasan a la función de vista los grupos con nombre.

Argumentos anidados

Expresiones regulares permiten argumentos anidados, y Django resolverá los mismos e incluirá los resultados en la vista. Al reescribir una URL, Django intentará llenar todos los argumentos capturados externos, ignorando cualquier argumento capturado anidado. Considera los siguientes patrones de URL que opcionalmente toman un argumento de página:

from django.urls import re_path

urlpatterns = [
    re_path(r"^blog/(page-([0-9]+)/)?$", blog_articles),  # bad
    re_path(r"^comments/(?:page-(?P<page_number>[0-9]+)/)?$", comments),  # good
]

Los textos traducidos son:

La vista blog_articles necesita que el argumento capturado más externo se invierta, page-2/ o sin argumentos en este caso, mientras que comments puede invertirse con o sin argumentos o un valor para page_number.

Los argumentos capturados anidados crean una fuerte acoplagación entre los argumentos de la vista y la URL, como se ilustra en blog_articles: la vista recibe parte de la URL (page-2/) en lugar de solo el valor que la vista necesita. Esta acoplagación es aún más pronunciada al invertir, ya que para invertir la vista necesitamos pasar la pieza de la URL en lugar del número de página.

Como regla general, solo capture los valores que la vista necesita trabajar con y utilice argumentos no capturadores cuando la expresión regular necesita un argumento pero la vista lo ignora.

¿Qué busca el URLconf?

El URLconf busca contra la URL solicitada, como una cadena de Python normal. Esto no incluye parámetros GET o POST, ni el nombre del dominio.

Por ejemplo, en una solicitud a https://www.example.com/myapp/, el URLconf buscará myapp/.

En una solicitud a https://www.example.com/myapp/?page=3, el URLconf buscará myapp/.

El URLconf no mira al método de solicitud. En otras palabras, todos los métodos de solicitud – POST, GET, HEAD, etc. – se enrutarán a la misma función para la misma URL.

Especificar valores por defecto para argumentos de vistas

Una convenientia es especificar parámetros por defecto para los argumentos de tus vistas. Aquí tienes un ejemplo de archivo URL y vista:

# URLconf
from django.urls import path

from . import views

urlpatterns = [
    path("blog/", views.page),
    path("blog/page<int:num>/", views.page),
]


# View (in blog/views.py)
def page(request, num=1):
    # Output the appropriate page of blog entries, according to num.
    ...

En el ejemplo anterior, ambos patrones de URL apuntan a la misma vista – views.page – pero el primer patrón no captura nada del URL. Si el primer patrón coincide, la función page() utilizará su argumento por defecto para num, que es 1. Si el segundo patrón coincide, page() utilizará el valor de num que se haya capturado.

Rendimiento

Django procesa expresiones regulares en la lista urlpatterns que se compila la primera vez que se accede a ella. Las solicitudes subsiguientes utilizan la configuración cacheada mediante el resolutor de URL.

Sintaxis de la variable urlpatterns

urlpatterns debe ser una secuencia de instancias de path() y/o re_path().

Gestión de errores

Cuando Django no encuentra un match para la URL solicitada, o cuando se levanta una excepción, Django invoca una vista de error.

Las vistas a utilizar en estos casos están especificadas por cuatro variables. Sus valores por defecto deberían ser suficientes para la mayoría de los proyectos, pero es posible realizar una personalización más profunda sobreescribiendo sus valores por defecto.

Para obtener más detalles, consulta la documentación sobre personalizar vistas de error.

Estos valores se pueden establecer en tu archivo URL raíz. Establecer estos variables en cualquier otro archivo URL no tendrá efecto.

Los valores deben ser llamables o cadenas de caracteres que representen el import path completo a la vista que se debe llamar para manejar la condición de error en cuestión.

Las variables son:

Incluir otros URLconfs

En cualquier momento, tus urlpatterns pueden «incluir» otros módulos de URLconf. Esto esencialmente «raíces» un conjunto de URLs debajo de otras.

Por ejemplo, aquí tienes un extracto del URLconf para el sitio web Django en sí mismo. Incluye varios otros URLconfs:

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path("community/", include("aggregator.urls")),
    path("contact/", include("contact.urls")),
    # ... snip ...
]

Cuando Django encuentra include(), corta lo que se ha encontrado hasta ese punto y envía la cadena restante al URLconf incluido para su procesamiento adicional.

Otra posibilidad es incluir patrones de URL adicionales utilizando una lista de instancias de la función path(). Por ejemplo, considera este archivo URLconf:

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path("reports/", credit_views.report),
    path("reports/<int:id>/", credit_views.report),
    path("charge/", credit_views.charge),
]

urlpatterns = [
    path("", main_views.homepage),
    path("help/", include("apps.help.urls")),
    path("credit/", include(extra_patterns)),
]

En este ejemplo, la URL /credit/reports/ será gestionada por la vista Django credit_views.report().

Esto se puede utilizar para eliminar redundancia de los archivos URLconfs donde un prefijo de patrón único se utiliza repetidamente. Por ejemplo, considera este archivo URLconf:

from django.urls import path
from . import views

urlpatterns = [
    path("<page_slug>-<page_id>/history/", views.history),
    path("<page_slug>-<page_id>/edit/", views.edit),
    path("<page_slug>-<page_id>/discuss/", views.discuss),
    path("<page_slug>-<page_id>/permissions/", views.permissions),
]

Podemos mejorar esto estando el prefijo de la ruta común solo una vez y agrupando las sufijas que difieren:

from django.urls import include, path
from . import views

urlpatterns = [
    path(
        "<page_slug>-<page_id>/",
        include(
            [
                path("history/", views.history),
                path("edit/", views.edit),
                path("discuss/", views.discuss),
                path("permissions/", views.permissions),
            ]
        ),
    ),
]

Parámetros capturados

Un archivo URL incluido recibe cualquier parámetro capturado de los archivos URLconfs padre, por lo que el siguiente ejemplo es válido:

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path("<username>/blog/", include("foo.urls.blog")),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path("", views.blog.index),
    path("archive/", views.blog.archive),
]

En el ejemplo anterior, el parámetro capturado "username" se pasa al archivo URL incluido, como se espera.

Pasando opciones adicionales a las funciones de vistas

Los archivos URLconfs tienen un hook que te permite pasar argumentos extra a tus funciones de vista, como un diccionario de Python.

La función path() puede tomar un tercer argumento opcional que debería ser un diccionario de argumentos de palabra clave adicionales para pasar a la función de vista.

Por ejemplo:

from django.urls import path
from . import views

urlpatterns = [
    path("blog/<int:year>/", views.year_archive, {"foo": "bar"}),
]

En este ejemplo, para una solicitud a /blog/2005/, Django llamará a views.year_archive(request, year=2005, foo='bar').

Esta técnica se utiliza en el framework de syndication para pasar metadatos y opciones a las vistas.

Resolviendo conflictos

Es posible tener un patrón de URL que captura argumentos de palabra clave nombrados, y también pasa argumentos con los mismos nombres en su diccionario de argumentos extra. Cuando esto sucede, los argumentos en el diccionario se utilizarán en lugar de los argumentos capturados en la URL.

Pasando opciones adicionales a include()

De manera similar, puedes pasar opciones adicionales a include() y cada línea en el URLconf incluido recibirá las opciones adicionales.

Por ejemplo, estos dos conjuntos de URLconf son funcionalmente idénticos:

Set uno:

# main.py
from django.urls import include, path

urlpatterns = [
    path("blog/", include("inner"), {"blog_id": 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path("archive/", views.archive),
    path("about/", views.about),
]

Set dos:

# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path("blog/", include("inner")),
]

# inner.py
from django.urls import path

urlpatterns = [
    path("archive/", views.archive, {"blog_id": 3}),
    path("about/", views.about, {"blog_id": 3}),
]

Ten en cuenta que las opciones adicionales siempre se pasarán a cada línea en el URLconf incluido, independientemente de si la vista acepta esas opciones como válidas. Por esta razón, esta técnica solo es útil si estás seguro de que cada vista en el URLconf incluido acepta las opciones adicionales que estás pasando.

Resolución inversa de URLs

Una necesidad común al trabajar en un proyecto Django es la posibilidad de obtener las URLs en sus formas finales, ya sea para insertarlas en contenido generado (URLs de vistas y activos, URLs mostradas al usuario, etc.) o para el manejo del flujo de navegación en el lado del servidor (redirecciones, etc.)

Es altamente deseable evitar codificar estas URLs de forma rígida (una estrategia laboriosa, no escalable y propensa a errores). Igualmente peligrosa es la invención de mecanismos ad-hoc para generar URLs que sean paralelos al diseño descrito por el URLconf, lo que puede dar lugar a la producción de URLs que se vuelven obsoletas con el tiempo.

En otras palabras, se necesita un mecanismo DRY. Entre otros beneficios permitiría la evolución del diseño de las URLs sin tener que recorrer todo el código fuente del proyecto para buscar y reemplazar las URL obsoletas.

La pieza principal de información disponible para obtener una URL es una identificación (por ejemplo, el nombre) de la vista encargada de manejarla. Otras piezas de información que necesariamente deben participar en la búsqueda de la URL correcta son los tipos (posicional, por palabra clave) y valores de los argumentos de la vista.

Django proporciona una solución tal que el mapeador de URLs es el único repositorio del diseño de las URLs. Se le alimenta con su URLconf y luego se puede utilizar en ambas direcciones:

  • Comenzando con una URL solicitada por el usuario/navegador, llama a la vista Django correcta proporcionando cualquier argumento que pueda necesitar con sus valores extraídos de la URL.

  • Comenzando con la identificación de la correspondiente vista Django más los valores de los argumentos que se pasarían a ella, obtiene la URL asociada.

La primera es el uso que hemos estado discutiendo en las secciones anteriores. La segunda es lo que se conoce como resolución inversa de URLs, coincidencia de URL inversa, búsqueda de URL inversa o simplemente reversión de URL.

Django proporciona herramientas para realizar la reversión de URL que coinciden con las diferentes capas donde se necesitan las URLs:

  • Los textos traducidos manteniendo todas sus etiquetas intactas son:

  • En código Python: Utilizando la función reverse().

  • En código relacionado con el manejo de URLs de instancias de modelos Django a nivel superior: El método get_absolute_url().

Ejemplos

Considera nuevamente esta entrada en URLconf:

from django.urls import path

from . import views

urlpatterns = [
    # ...
    path("articles/<int:year>/", views.year_archive, name="news-year-archive"),
    # ...
]

Según este diseño, la URL para el archivo correspondiente al año nnnn es /artículos/<nnnn>/.

Puedes obtener estos en código de plantilla utilizando:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

O en código Python:

from django.http import HttpResponseRedirect
from django.urls import reverse


def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse("news-year-archive", args=(year,)))

Si por alguna razón se decidiera que las URLs donde se publican el contenido para archivos de archivo anual deberían cambiar, entonces solo necesitarías cambiar la entrada en el URLconf.

En algunos escenarios donde las vistas tienen una naturaleza genérica, puede existir una relación muchos-a-uno entre URLs y vistas. Para estos casos, el nombre de la vista no es un identificador suficiente cuando se trata de revertir las URLs. Lee la siguiente sección para saber sobre la solución que ofrece Django para este problema.

Nombrando patrones de URL

In order to perform URL reversing, you’ll need to use **named URL patterns as done in the examples above. The string used for the URL name can contain any characters you like. You are not restricted to valid Python names.**

When naming URL patterns, choose names that are unlikely to clash with other applications” choice of names. If you call your URL pattern ``comment`` and another application does the same thing, the URL that :func:`~django.urls.reverse()` finds depends on whichever pattern is last in your project’s ``urlpatterns`` list.

Putting a prefix on your URL names, perhaps derived from the application name (such as ``myapp-comment`` instead of ``comment``), decreases the chance of collision.

You can deliberately choose the *same URL name* as another application if you want to override a view. For example, a common use case is to override the :class:`~django.contrib.auth.views.LoginView`. Parts of Django and most third-party apps assume that this view has a URL pattern with the name ``login``. If you have a custom login view and give its URL the name ``login``, :func:`~django.urls.reverse()` will find your custom view as long as it’s in ``urlpatterns`` after ``django.contrib.auth.urls`` is included (if that’s included at all).

You may also use the same name for multiple URL patterns if they differ in their arguments. In addition to the URL name, :func:`~django.urls.reverse()` matches the number of arguments and the names of the keyword arguments. Path converters can also raise ``ValueError`` to indicate no match, see :ref:`registering-custom-path-converters` for details.

URL namespaces

Introduction

URL namespaces allow you to uniquely reverse :ref:`named URL patterns <naming-url-patterns>` even if different applications use the same URL names. It’s a good practice for third-party apps to always use namespaced URLs (as we did in the tutorial). Similarly, it also allows you to reverse URLs if multiple instances of an application are deployed. In other words, since multiple instances of a single application will share named URLs, namespaces provide a way to tell these named URLs apart.

Django applications that make proper use of URL namespacing can be deployed more than once for a particular site. For example :mod:`django.contrib.admin` has an :class:`~django.contrib.admin.AdminSite` class which allows you to :ref:`deploy more than one instance of the admin <multiple-admin-sites>`. In a later example, we’ll discuss the idea of deploying the polls application from the tutorial in two different locations so we can serve the same functionality to two different audiences (authors and publishers).

A URL namespace comes in two parts, both of which are strings:

application namespace

Este describe el nombre de la aplicación que se está desplegando. Cada instancia de una sola aplicación tendrá el mismo espacio de nombres de aplicación. Por ejemplo, la aplicación administrativa de Django tiene el espacio de nombres de aplicación algo predecible de 'admin'.

instance namespace

Esto identifica una instancia específica de una aplicación. Los espacios de nombres de instancia deben ser únicos en todo tu proyecto. Sin embargo, un espacio de nombres de instancia puede ser el mismo que el espacio de nombres de la aplicación. Esto se utiliza para especificar una instancia predeterminada de una aplicación. Por ejemplo, la instancia administrativa predeterminada de Django tiene un espacio de nombres de instancia de 'admin'.

Las URL con espacio de nombres se especifican utilizando el operador ':'. Por ejemplo, la página principal de inicio de la aplicación administrativa se referencia utilizando 'admin:index'. Esto indica un espacio de nombres de 'admin', y una URL nombrada de 'index'.

Los espacios de nombres también pueden estar anidados. La URL nombrada 'sports:polls:index' buscaría un patrón llamado 'index' en el espacio de nombres 'polls' que está definido dentro del espacio de nombres superior 'sports'.

Reversar URLs con espacio de nombres

Cuando se le da una URL con espacio de nombres (por ejemplo, 'polls:index') para resolver, Django divide el nombre completo en partes y luego intenta la siguiente búsqueda:

  1. Primero, Django busca un espacio de nombres de aplicación correspondiente (application namespace en este ejemplo, 'polls'). Esto producirá una lista de instancias de esa aplicación.

  2. Si hay una aplicación actual definida, Django encuentra y devuelve el resolutor de URL para esa instancia. La aplicación actual se puede especificar con la argumento current_app a la función reverse().

    The url template tag uses the namespace of the currently resolved view as the current application in a RequestContext. You can override this default by setting the current application on the request.current_app attribute.

  3. Si no hay una aplicación actual, Django busca una instancia de aplicación por defecto. La instancia de aplicación por defecto es la instancia que tiene un espacio de nombres de instancia que coincida con el espacio de nombres de aplicación (en este ejemplo, una instancia de polls llamada 'polls').

  4. Si no hay ninguna instancia de aplicación por defecto, Django elegirá la última instancia desplegada del aplicativo, independientemente de su nombre de instancia.

  5. Si el espacio de nombres proporcionado no coincide con un espacio de nombres de aplicación en el paso 1, Django intentará una búsqueda directa del espacio de nombres como un espacio de nombres de instancia.

Si hay espacios de nombres anidados, se repiten estos pasos para cada parte del espacio de nombres hasta que solo el nombre de la vista queda sin resolver. El nombre de la vista se resolverá entonces en una URL en el espacio de nombres que se ha encontrado.

Ejemplo

Para mostrar esta estrategia de resolución en acción, considera un ejemplo de dos instancias de la aplicación polls del tutorial: una llamada 'author-polls' y otra llamada 'publisher-polls'. Supongamos que hemos mejorado esa aplicación para que tenga en cuenta el espacio de nombres de instancia al crear y mostrar encuestas.

urls.py
from django.urls import include, path

urlpatterns = [
    path("author-polls/", include("polls.urls", namespace="author-polls")),
    path("publisher-polls/", include("polls.urls", namespace="publisher-polls")),
]
polls/urls.py
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.IndexView.as_view(), name="index"),
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ...,
]

Con este setup, se pueden realizar las siguientes búsquedas:

  • Si una de las instancias es actual - digamos que estamos renderizando la página de detalles en la instancia 'author-polls' - 'polls:index' se resolverá a la página de índice de la instancia 'author-polls'; es decir, tanto lo siguiente darán como resultado "/author-polls/".

    En el método de una vista basada en clase:

    reverse("polls:index", current_app=self.request.resolver_match.namespace)
    

    y en el template:

    {% url 'polls:index' %}
    
  • Si no hay una instancia actual - digamos, si estábamos renderizando una página en otra parte del sitio - 'polls:index' se resolverá a la última instancia registrada de polls. Dado que no existe una instancia predeterminada (espacio de nombres de instancia de 'polls'), se utilizará la última instancia de polls que esté registrada. Esto sería 'publisher-polls' ya que está declarado último en las urlpatterns.

  • “author-polls:index” siempre se resolverá a la página de inicio de la instancia ` “author-polls”` (y lo mismo sucede con “publisher-polls”).

Si también hubiera una instancia por defecto - es decir, una instancia llamada 'polls' - la única modificación con respecto a lo anterior sería en el caso donde no hay ninguna instancia actual (el segundo elemento de la lista anterior). En este caso 'polls:index' se resolvería a la página de índice de la instancia por defecto en lugar de la última instancia declarada en urlpatterns.

Nombres de espacio de URLs y URLconfs incluidos

Nombres de espacio de la aplicación de las URLconfs incluidas pueden especificarse de dos maneras.

Primero, puedes establecer un atributo app_name en el módulo de URLconf incluido, al mismo nivel que el atributo urlpatterns. Tienes que pasar el módulo real o una referencia como cadena al módulo, a include(), no la lista de urlpatterns misma.

polls/urls.py
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.IndexView.as_view(), name="index"),
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ...,
]
urls.py
from django.urls import include, path

urlpatterns = [
    path("polls/", include("polls.urls")),
]

Las URL definidas en polls.urls tendrán un espacio de nombres de aplicación polls.

Segundo, puedes incluir un objeto que contenga datos de espacio de nombres incorporados. Si incluyes mediante include() una lista de instancias de path() o re_path(), los URLs contenidos en ese objeto se agregarán al espacio de nombres global. Sin embargo, también puedes include() un 2-tuple que contenga:

(<list of path()/re_path() instances>, <application namespace>)

Por ejemplo:

from django.urls import include, path

from . import views

polls_patterns = (
    [
        path("", views.IndexView.as_view(), name="index"),
        path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ],
    "polls",
)

urlpatterns = [
    path("polls/", include(polls_patterns)),
]

Incluirá los patrones de URL nominados en el espacio de nombres de la aplicación dada.

La instancia de namespace se puede especificar utilizando el argumento namespace a la función include(). Si no se especifica la instancia de namespace, será el valor por defecto del namespace de aplicación del URLconf incluido. Esto significa que también será la instancia predeterminada para ese namespace.