Como posso obter a URL completa / absoluta (com domínio) no Django?

379

Como posso obter a URL completa / absoluta (por exemplo https://example.com/some/path) no Django sem o módulo Sites ? Isso é bobagem ... Eu não deveria precisar consultar meu banco de dados para pegar o URL!

Eu quero usá-lo com reverse().

mpen
fonte
11
Apenas como um aparte: o módulo sites atinge apenas o banco de dados na primeira vez em que precisa do nome do site, o resultado é armazenado em cache em uma variável de módulo (SITE_CACHE) que permanecerá até a recompilação do módulo ou do SiteManager.clear_cache () método é chamado. Veja: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Coronel Sponsz

Respostas:

512

Use o método request.build_absolute_uri () , a pedido, transmita o URL relativo e ele fornecerá um completo.

Por padrão, a URL absoluta para request.get_full_path()é retornada, mas você pode passar uma URL relativa como o primeiro argumento para convertê-la em uma URL absoluta.

Dmitry Shevchenko
fonte
3
E o URL: localhost / home / # / test ? Eu posso ver apenas localhost / home . Como posso ver a peça depois de afiada ?
sergzach 18/09/11
41
tudo após # não é passado para o servidor, é recurso só-browser
Dmitry Shevchenko
70
Em um modelo (onde você não pode fornecer parâmetros), você pode simplesmente fazer o seguinte: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- e heyho, URL completo.
odinho - Velmont
17
E se eu não tiver acesso para solicitar? Como nos serializadores do Django-REST-Framework?
minder
15
Eu tive que usar {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}porque {{ request.build_absolute_uri }}tinha uma barra à direita e {{ object.get_absolute_url }}comecei com uma barra, resultando em barras duplas no URL.
Xtranophilist
96

Se você quiser usá- reverse()lo, faça o seguinte:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))

ébewè
fonte
3
Obrigado pela resposta útil. Nada melhor que o próprio código. (também, você provavelmente quis dizer em url_namevez de view_name) #
Anupam
3
@Anupam reverse () é definido como:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart 31/01
57

Você também pode usar get_current_sitecomo parte do aplicativo de sites ( from django.contrib.sites.models import get_current_site). Ele pega um objeto de solicitação e o padrão é o objeto de site com o qual você configurou SITE_IDem settings.py, se solicitado None. Leia mais na documentação para usar a estrutura de sites

por exemplo

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

Não é tão compacto / elegante quanto request.build_absolute_url(), mas é utilizável quando os objetos de solicitação não estão disponíveis e você tem um URL de site padrão.

Darb
fonte
4
Acredito que minha pergunta dizia especificamente "sem o módulo Sites". Isso atinge o banco de dados?
MPEN
11
O módulo Sites foi gravado para armazenar em cache objetos do Site usando o cache no nível do módulo (ou seja, você não precisa da estrutura de cache); portanto, o banco de dados deve ser atingido apenas na primeira vez que um Site for recuperado por um processo da Web. Se você não tem django.contrib.sitesna sua INSTALLED_APPS, não vai bater o DB em tudo, e fornecer informações com base no objeto Request (veja get_current_site )
Darb
11
Bem, então você pode ter um +1, mas build_absolute_uriainda parece a solução mais fácil e limpa.
MJ #
11
Essa é uma resposta perfeita se você estiver tentando gerar URLs em sinais dos quais enviar emails.
Chris
2
Não funciona, se você usar https. Sim, você pode adicionar os s, mas você desenvolve com https localmente? e você sempre sabe, se você tem https, mas às vezes não ...?
tjati 5/05
55

Se você não conseguir acessar request, não poderá usá-lo get_current_site(request)conforme recomendado em algumas soluções aqui. Você pode usar uma combinação da estrutura nativa de Sites get_absolute_url. Configure pelo menos um site no administrador, verifique se o seu modelo possui um método get_absolute_url () e , em seguida:

>>> 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
fonte
7
Isso é realmente útil quando você não tem acesso ao objeto HttpRequest. por exemplo, em tarefas, sinais etc.
Arsham 11/11
6
antes de usar isso, você deve permitir que sites de enquadramento docs.djangoproject.com/en/dev/ref/contrib/sites/...
madzohan
Para alterar example.com para algo também: Site.objects.all () [0] retorna 'example.com' e possui id = 1, especificado em settings.py. Basta fazer Site.objects.create (nome = 'produção', domínio = 'prodsite.com') e defina SITE_ID = 2 em settings.py. Agora Site.objects.get_current (). Domain retorna 'prodsite.com'.
gek
Você pode definir requesta Noneou chamada get_current_site(None).
Bobort 24/03
20

Se você não quiser acessar o banco de dados, poderá fazê-lo com uma configuração. Em seguida, use um processador de contexto para adicioná-lo a todos os modelos:

# 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
fonte
17

Na sua opinião, faça o seguinte:

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

django-fullurl

Se você está tentando fazer isso em um modelo do Django, lançamos um pequeno pacote PyPI django-fullurlpara permitir a substituição urle as statictags de modelos por fullurle fullstatic, assim:

{% load fullurl %}

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

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

Espera-se que esses emblemas se mantenham atualizados automaticamente:

PyPI Travis CI

Em uma exibição, é claro que você pode usar request.build_absolute_uri.

Flimm
fonte
Pena que isso não funciona com o 2.0. Pode ser necessário fazer um PR.
9188 Steven Church
@StevenChurch Deve funcionar. Ainda não marquei o Django 2.0 como suportado, mas a versão existente deve funcionar.
Flimm
Para minhas necessidades, resolvi isso passando um ENV da Heroku para failback. Meu problema é fazer com que o URL passe para os modelos de email. Não me lembro do problema, mas não funcionou devido a uma alteração no Django.
Steven Church
@StevenChurch Acho que o problema ao criar e-mails é que não há nenhum requestobjeto para obter o nome de domínio. Nesse caso, você deve usar a sitesestrutura, que obtém o nome de domínio do banco de dados. Consulte django-absoluteuri, mencionado na seção "consulte também" do README deste pacote PyPI.
Flimm
8

Para criar um link completo para outra página a partir de um modelo, você pode usar este:

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

request.META.HTTP_HOST fornece o nome do host e url fornece o nome relativo. O mecanismo do modelo concatena-os em um URL completo.

Doug Bradshaw
fonte
2
A resposta está faltando o protocolo ( httpneste contexto) e ://parte do URL, portanto, ele não fornecerá um URL completo .
user272735
2
O objeto de solicitação possui um host. Não examine meta diretamente: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde
8

Mais uma maneira. Você pode usar build_absolute_uri()no seu view.pye passá-lo para o modelo.

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
fonte
HttpRequest.build_absolute_uri(request)é equivalente a request.build_absolute_uri()não é?
MPEN
7

Examine o Request.METAdicionário que entra. Acho que tem nome e porta do servidor.

Kugel
fonte
2
use request.META ['HTTP_HOST']
Antony
4
O objeto de solicitação possui um host. Não examine meta diretamente: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde
7

Tente o seguinte código:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}
marca
fonte
Isso apenas fornecerá o domínio sem o caminho e a string de consulta, não?
MPEN
6

Isso funcionou para mim no meu modelo:

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

Eu precisava do URL completo para passá-lo para uma função js fetch. Espero que isso lhe ajude.

Jose Luis Quichimbo
fonte
5

Eu sei que esta é uma pergunta antiga. Mas acho que as pessoas ainda se deparam muito com isso.

Existem algumas bibliotecas por aí que complementam a funcionalidade padrão do Django. Eu tentei alguns. Gosto da seguinte biblioteca ao fazer referência inversa a URLs absolutos:

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

Outro que eu gosto, porque você pode facilmente montar um domínio, protocolo e caminho é:

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

Esta biblioteca permite que você simplesmente escreva o que deseja em seu modelo, por exemplo:

{{url_parts.domain}}
johniak20
fonte
4

Se você estiver usando a estrutura REST do django, poderá usar a função reversa de rest_framework.reverse. Isso tem o mesmo comportamento que django.core.urlresolvers.reverse, exceto que ele usa um parâmetro de solicitação para criar um URL completo.

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 disponibilidade apenas na estrutura REST

JohnG
fonte
Eu recebo um erro ao usar request=request. Ele também não parece ser pedido está documentado aqui docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos
Esqueci de mencionar que isso só está disponível se você estiver usando a estrutura REST. Boa captura, eu atualizei minha resposta.
JohnG 22/05
Sim, obrigado - isso funciona como um encanto com o framework REST do django
Apoorv Kansal
1

Deixa comigo:

wsgiref.util.request_uri(request.META)

Obtenha a interface do usuário completa com esquema, host, caminho da porta e consulta.

maravilha
fonte
0

Também há ABSOLUTE_URL_OVERRIDES disponível como uma configuração

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

Mas isso substitui get_absolute_url (), o que pode não ser desejável.

Em vez de instalar a estrutura de sites apenas para isso ou fazer algumas das outras coisas mencionadas aqui que dependem do objeto de solicitação, acho que a melhor solução é colocá-lo no models.py

Defina BASE_URL em settings.py, depois importe-o para models.py e crie uma classe abstrata (ou adicione-a a uma que você já esteja usando) que define get_truly_absolute_url (). Pode ser tão simples quanto:

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

Subclasse e agora você pode usá-lo em qualquer lugar.

aris
fonte
0

Conforme mencionado em outras respostas, request.build_absolute_uri()é perfeito se você tiver acesso requestesites estrutura é excelente, desde que URLs diferentes apontem para bancos de dados diferentes.

No entanto, meu caso de uso foi um pouco diferente. Meu servidor intermediário e o servidor de produção acessam o mesmo banco de dados, mas get_current_siteambos retornaram o primeiro siteno banco de dados. Para resolver isso, você precisa usar algum tipo de variável de ambiente. Você pode usar 1) uma variável de ambiente (algo como os.environ.get('SITE_URL', 'localhost:8000')) ou 2) SITE_IDs diferentes para servidores diferentes E settings.py diferentes .

Espero que alguém ache isso útil!

Bartleby
fonte
0

Me deparei com esse segmento porque estava procurando criar um URI absoluto para uma página de sucesso. request.build_absolute_uri()me deu um URI para minha visão atual, mas para obter a URI para minha visão de sucesso, usei o seguinte ....

request.build_absolute_uri (reverse ('success_view_name'))

Soundtemple
fonte
-2

request.get_host() lhe dará o domínio.

Roge
fonte
11
A pergunta afirma, URL completo
acidjunk 5/16/16
-5

Você também pode usar:

import socket
socket.gethostname()

Isso está funcionando bem para mim,

Não tenho muita certeza de como isso funciona. Acredito que este seja um nível um pouco mais baixo e retornará o nome do host do servidor, que pode ser diferente do nome do host usado pelo usuário para acessar sua página.

Eduardo
fonte
Sim ... você apontou o problema. Nome do host não é necessariamente o mesmo que o nome do domínio.
MPEN
Isso resolve um problema muito diferente. Considere um servidor de hospedagem compartilhada com vários sites - usando o código acima, todos os sites que geram URLs terão todos esses URLs apontando para a máquina host, o que provavelmente NÃO é um dos sites em execução.
tbm
-6

Você pode tentar "request.get_full_path ()"

Max Ferreira
fonte
3
Isso não inclui o domínio.
TAH