O contexto (mas não é uma questão exclusiva do Django) é que o servidor de teste do Django não retorna um esquema ou netloc em suas URLs de resposta e solicitação.
Eu pego /foo/bar
por exemplo, e quero terminar com http://localhost:8000/foo/bar
.
urllib.parse.urlparse
(mas não tanto urllib.parse.urlsplit
) facilita a coleta de informações relevantes, a partir da URL de teste e do endereço do meu servidor conhecido. O que parece mais complicado do que o necessário é recompor uma nova URL com o esquema e o netloc adicionados via urllib.parse.urlcompose , que precisa de argumentos posicionais, mas não documenta quais são, nem suporta argumentos nomeados. Enquanto isso, as funções de análise retornam tuplas imutáveis...
def urlunparse(components):
"""Put a parsed URL back together again. This may result in a ..."""
Consegui fazer funcionar, veja o código abaixo, mas parece muito desajeitado, na parte em que preciso primeiro transformar as tuplas de análise em listas e depois modificar a lista na posição de índice necessária.
Existe uma maneira mais pitônica?
código de exemplo:
from urllib.parse import urlsplit, parse_qs, urlunparse, urlparse, urlencode, ParseResult, SplitResult
server_at_ = "http://localhost:8000"
url_in = "/foo/bar" # this comes from Django test framework I want to change this to "http://localhost:8000/foo/bar"
from_server = urlparse(server_at_)
print(" scheme and netloc from server:",from_server)
print(f"{url_in=}")
from_urlparse = urlparse(url_in)
print(" missing scheme and netloc:",from_urlparse)
#this works
print("I can rebuild it unchanged :",urlunparse(from_urlparse))
#however, using the modern urlsplit doesnt work (I didn't know about urlunsplit when asking)
try:
print("using urlsplit", urlunparse(urlsplit(url_in)))
#pragma: no cover pylint: disable=unused-variable
except (Exception,) as e:
print("no luck with urlsplit though:", e)
#let's modify the urlparse results to add the scheme and netloc
try:
from_urlparse.scheme = from_server.scheme
from_urlparse.netloc = from_server.netloc
new_url = urlunparse(from_urlparse)
except (Exception,) as e:
print("can't modify tuples:", e)
# UGGGH, this works, but is there a better way?
parts = [v for v in from_urlparse]
parts[0] = from_server.scheme
parts[1] = from_server.netloc
print("finally:",urlunparse(parts))
saída de exemplo:
scheme and netloc from server: ParseResult(scheme='http', netloc='localhost:8000', path='', params='', query='', fragment='')
url_in='/foo/bar'
missing scheme and netloc: ParseResult(scheme='', netloc='', path='/foo/bar', params='', query='', fragment='')
I can rebuild it unchanged : /foo/bar
no luck with urlsplit though: not enough values to unpack (expected 7, got 6)
can't modify tuples: can't set attribute
finally: http://localhost:8000/foo/bar
Se você precisar disso no Django, encontrei request.build_absolute_uri() em questão
Como posso obter a URL completa/absoluta (com domínio) no Django? - Stack Overflow
Não testei, mas talvez resolva esse problema no Django.
Outros módulos/frameworks também podem ter funções próprias para isso.
Como me lembro, o módulo
scrapy
para scraping de HTML tem uma função própriaresponse.urljoin()
para converter URL relativa em URL absoluta.Quanto às funções no módulo
urllib
:Você teria que usar
urlsplit
comurlunsplit
(que usam menos valores)urlparse
comurlunparse
(que usam mais valores)Há uma função "oculta"
_replace()
que cria um novo ParseResult com valores substituídos.Normalmente eu preciso apenas de urljoin()