¿Cómo puedo obtener la URL completa / absoluta (con dominio) en Django?

379

¿Cómo puedo obtener la URL completa / absoluta (por ejemplo https://example.com/some/path) en Django sin el módulo Sitios ? Eso es una tontería ... ¡No debería necesitar consultar mi base de datos para enganchar la URL!

Quiero usarlo con reverse().

mpen
fuente
11
Solo como un aparte: el módulo de sitios solo llega a la base de datos la primera vez que necesita el nombre del sitio, el resultado se almacena en caché en una variable de módulo (SITE_CACHE) que se mantendrá hasta la nueva compilación del módulo o SiteManager.clear_cache () Se llama al método. Ver: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Coronel Sponsz

Respuestas:

513

Utilice el práctico método request.build_absolute_uri () a pedido, páselo por la URL relativa y le dará una completa.

De forma predeterminada, request.get_full_path()se devuelve la URL absoluta para , pero puede pasarle una URL relativa como primer argumento para convertirla en una URL absoluta.

Dmitry Shevchenko
fuente
3
¿Qué pasa con la url: localhost / home / # / test ? Solo puedo ver localhost / home . ¿Cómo puedo ver la parte después de afilada ?
sergzach
41
todo después de # no se pasa al servidor, es una función exclusiva del navegador
Dmitry Shevchenko
70
En una plantilla (donde no puede dar parámetros) puede hacer esto: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- y heyho, url completa.
odinho - Velmont
17
¿Y si no tengo acceso a la solicitud? ¿Como en los serializadores de Django-REST-Framework?
minder
15
Tuve que usar {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}porque {{ request.build_absolute_uri }}tenía una barra inclinada final y {{ object.get_absolute_url }}comencé con una barra diagonal que resultó en barras diagonales dobles en la URL.
xtranophilist
97

Si quieres usarlo reverse()puedes hacerlo:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))

ébewè
fuente
3
Gracias por la útil respuesta. Nada mejor que el código en sí. (también, probablemente quisiste decir en url_namelugar de view_name)
Anupam
3
@Anupam reverse () se define como:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart
57

También puede usarlo get_current_sitecomo parte de la aplicación de sitios ( from django.contrib.sites.models import get_current_site). Toma un objeto de solicitud, y por defecto es el objeto de sitio que ha configurado SITE_IDen settings.py si la solicitud es None. Lea más en la documentación para usar el framework de sitios

p.ej

from django.contrib.sites.shortcuts import get_current_site
request = None
full_url = ''.join(['http://', get_current_site(request).domain, obj.get_absolute_url()])

No es tan compacto / ordenado como request.build_absolute_url(), pero se puede usar cuando los objetos de solicitud no están disponibles y tiene una URL de sitio predeterminada.

Darb
fuente
44
Creo que mi pregunta decía específicamente "sin el módulo Sitios". ¿Esto golpea el DB?
mpen
1
El módulo de Sitios se ha escrito en la memoria caché de los objetos del Sitio utilizando el almacenamiento en caché a nivel de módulo (es decir, no necesita el marco de la memoria caché), por lo que la base de datos solo debería verse afectada la primera vez que un proceso web recupera un Sitio. Si no tiene django.contrib.sitesen su INSTALLED_APPS, no llegará a la base de datos en absoluto, y proporcionará información basada en el objeto Solicitud (consulte get_current_site )
Darb
1
Bueno, entonces puedes tener un +1, pero build_absolute_uriaún parece la solución más fácil y limpia.
mpen
1
Esta es una respuesta perfecta si está tratando de generar URL en señales para enviar correos electrónicos.
Chris
2
No funciona, si usas https. Sí, podrías agregar el s, pero ¿desarrollas con https localmente? y siempre sabes, si tienes https pero no a veces ...?
tjati
55

Si no puede acceder, requestentonces no puede usar get_current_site(request)como se recomienda en algunas soluciones aquí. Puede utilizar una combinación del marco de Sitios nativo y en su get_absolute_urllugar. Configure al menos un sitio en el administrador, asegúrese de que su modelo tenga un método get_absolute_url () , luego:

>>> from django.contrib.sites.models import Site
>>> domain = Site.objects.get_current().domain
>>> obj = MyModel.objects.get(id=3)
>>> path = obj.get_absolute_url()

>>> url = 'http://{domain}{path}'.format(domain=domain, path=path)
>>> print(url)
'http://example.com/mymodel/objects/3/'

https://docs.djangoproject.com/en/dev/ref/contrib/sites/#getting-the-current-domain-for-full-urls

shacker
fuente
77
Esto es realmente útil cuando no tiene acceso al objeto HttpRequest. por ejemplo, en tareas, señales, etc.
Arsham
66
antes de usar esto, debe habilitar el framework de sitios docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan
Para cambiar example.com a algo también: Site.objects.all () [0] devuelve 'example.com' y tiene id = 1, que se especificó en settings.py. Simplemente haga Site.objects.create (name = 'production', domain = 'prodsite.com') y configure SITE_ID = 2 en settings.py. Ahora Site.objects.get_current (). Dominio devuelve 'prodsite.com'.
gek
Se puede establecer requestque Noneo llame get_current_site(None).
Bobort
20

Si no desea acceder a la base de datos, puede hacerlo con una configuración. Luego, use un procesador de contexto para agregarlo a cada plantilla:

# settings.py (Django < 1.9)
...
BASE_URL = 'http://example.com'
TEMPLATE_CONTEXT_PROCESSORS = (
    ...
    'myapp.context_processors.extra_context',
)
# settings.py (Django >= 1.9)
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                # Additional
                'myapp.context_processors.extra_context',
            ],
        },
    },
]

# myapp/context_processors.py
from django.conf import settings

def extra_context(request):
    return {'base_url': settings.BASE_URL}

# my_template.html
<p>Base url is {{ base_url }}.</p>
seddonym
fuente
17

En su opinión, solo haga esto:

base_url =  "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
levi
fuente
14

django-fullurl

Si está tratando de hacer esto en una plantilla de Django, he lanzado un pequeño paquete PyPI django-fullurlpara permitirle reemplazar urly staticetiquetas de plantilla con fullurly fullstatic, de esta manera:

{% load fullurl %}

Absolute URL is: {% fullurl "foo:bar" %}

Another absolute URL is: {% fullstatic "kitten.jpg" %}

Es de esperar que estas insignias se mantengan actualizadas automáticamente:

PyPI Travis CI

En una vista, por supuesto, puede usar request.build_absolute_urien su lugar.

Flimm
fuente
Es una pena que esto no funcione con 2.0. Puede que tenga que subir un PR.
Steven Church
@StevenChurch Debería funcionar. Todavía no he marcado Django 2.0 como compatible, pero la versión existente debería funcionar.
Flimm
Para mis necesidades, resolví esto al pasar un ENV de Heroku para recuperación. Mi problema es hacer que la URL pase a las plantillas de correo electrónico. No recuerdo el problema, pero no funcionó debido a un cambio de Django.
Steven Church
@StevenChurch Creo que el problema al crear correos electrónicos es que no hay ningún requestobjeto para obtener el nombre de dominio. En ese caso, debe usar el sitesmarco en su lugar, que obtiene el nombre de dominio de la base de datos. Ver django-absoluteuri, mencionado en la sección "ver también" del archivo README de este paquete PyPI.
Flimm
8

Para crear un enlace completo a otra página desde una plantilla, puede usar esto:

{{ request.META.HTTP_HOST }}{% url 'views.my_view' my_arg %}

request.META.HTTP_HOST proporciona el nombre del host y url proporciona el nombre relativo. El motor de plantillas los concatena en una url completa.

Doug Bradshaw
fuente
2
A la respuesta le falta el protocolo ( httpen este contexto) y ://parte de la URL, por lo que no proporcionará una URL completa .
user272735
2
El objeto de solicitud tiene un host. No examine meta directamente: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde
8

Otra forma más. Puede usar build_absolute_uri()en su view.pyy pasarlo a la plantilla.

view.py

def index(request):
    baseurl = request.build_absolute_uri()
    return render_to_response('your-template.html', { 'baseurl': baseurl })

your-template.html

{{ baseurl }}
Sven Rojek
fuente
HttpRequest.build_absolute_uri(request)es equivalente a request.build_absolute_uri()no es así?
mpen
7

Examine el Request.METAdiccionario que viene. Creo que tiene el nombre del servidor y el puerto del servidor.

Kugel
fuente
2
use request.META ['HTTP_HOST']
Antony
44
El objeto de solicitud tiene un host. No examine meta directamente: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde
7

Prueba el siguiente código:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}
marca
fuente
Eso solo le dará al dominio sin la ruta y la cadena de consulta, ¿no?
mpen
6

Esto funcionó para mí en mi plantilla:

{{ request.scheme }}:{{ request.META.HTTP_HOST }}{% url  'equipos:marca_filter' %}

Necesitaba la url completa para pasarla a una función js fetch. Espero que esto te ayude.

Jose Luis Quichimbo
fuente
5

Sé que esta es una vieja pregunta. Pero creo que la gente todavía se encuentra con esto mucho.

Hay un par de bibliotecas que complementan la funcionalidad predeterminada de Django. He intentado algunos. Me gusta la siguiente biblioteca cuando se hace referencia inversa a las URL absolutas:

https://github.com/fusionbox/django-absoluteuri

Otro que me gusta porque puedes armar fácilmente un dominio, protocolo y ruta es:

https://github.com/RRMoelker/django-full-url

Esta biblioteca le permite simplemente escribir lo que quiera en su plantilla, por ejemplo:

{{url_parts.domain}}
johniak20
fuente
4

Si está utilizando django REST framework, puede utilizar la función inversa de rest_framework.reverse. Tiene el mismo comportamiento que django.core.urlresolvers.reverse, excepto que utiliza un parámetro de solicitud para crear una URL completa.

from rest_framework.reverse import reverse

# returns the full url
url = reverse('view_name', args=(obj.pk,), request=request)

# returns only the relative url
url = reverse('view_name', args=(obj.pk,))

Editado para mencionar la disponibilidad solo en el marco REST

JohnG
fuente
Me sale un error al usar request=request. Tampoco parece que la solicitud esté documentada aquí docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos
Olvidé mencionar que esto solo está disponible si está utilizando el marco REST. Buena captura, he actualizado mi respuesta.
JohnG
Sí, gracias. Esto funciona a las
mil maravillas
1

Lo tengo:

wsgiref.util.request_uri(request.META)

Obtenga la uri completa con esquema, host, ruta de puerto y consulta.

preguntarse
fuente
0

También hay ABSOLUTE_URL_OVERRIDES disponibles como configuración

https://docs.djangoproject.com/en/2.1/ref/settings/#absolute-url-overrides

Pero eso anula get_absolute_url (), lo que puede no ser deseable.

En lugar de instalar el framework de sitios solo para esto o hacer algunas de las otras cosas mencionadas aquí que se basan en el objeto de solicitud, creo que la mejor solución es colocar esto en models.py

Defina BASE_URL en settings.py, luego impórtelo en models.py y cree una clase abstracta (o agréguela a una que ya esté usando) que defina get_truly_absolute_url (). Podría ser tan simple como:

def get_truly_absolute_url(self):
    return BASE_URL + self.get_absolute_url()

Subclasifícalo y ahora puedes usarlo en todas partes.

aris
fuente
0

Como se menciona en otras respuestas, request.build_absolute_uri()es perfecto si tiene acceso a él request, y el sitesmarco es excelente siempre que diferentes URL apunten a diferentes bases de datos.

Sin embargo, mi caso de uso fue ligeramente diferente. Mi servidor provisional y el servidor de producción acceden a la misma base de datos, pero get_current_siteambos devolvieron el primero siteen la base de datos. Para resolver esto, debe usar algún tipo de variable de entorno. Puede usar 1) una variable de entorno (algo así como os.environ.get('SITE_URL', 'localhost:8000')) o 2) diferentes SITE_IDs para diferentes servidores Y diferentes configuraciones.py .

¡Espero que alguien encuentre esto útil!

Bartleby
fuente
0

Encontré este hilo porque estaba buscando construir un URI absoluto para una página de éxito. request.build_absolute_uri()me dio un URI para mi vista actual pero para obtener el URI para mi vista de éxito usé lo siguiente ...

request.build_absolute_uri (reverse ('success_view_name'))

Soundtemple
fuente
-2

request.get_host() te dará el dominio.

Roge
fuente
1
La pregunta dice, URL completa
acidjunk 05 de
-5

También puedes usar:

import socket
socket.gethostname()

Esto está funcionando bien para mí

No estoy completamente seguro de cómo funciona. Creo que este es un nivel un poco más bajo y devolverá el nombre de host de su servidor, que podría ser diferente al nombre de host utilizado por su usuario para llegar a su página.

Eduardo
fuente
Sí ... usted señaló el problema. El nombre de host no es necesariamente el mismo que el nombre de dominio.
mpen
Esto resuelve un problema muy diferente. Considere un servidor de alojamiento compartido con múltiples sitios web: utilizando el código anterior, todos los sitios que generan URL tendrán todas esas URL apuntando a la máquina host, que probablemente NO sea ninguno de los sitios web en ejecución.
tbm
-6

Puedes probar "request.get_full_path ()"

Max Ferreira
fuente
3
Esto no incluye el dominio.
TAH