Come posso ottenere l'URL completo / assoluto (con dominio) in Django?


379

Come posso ottenere l'URL completo / assoluto (ad es. https://example.com/some/path) In Django senza il modulo Sites ? È solo stupido ... Non dovrei aver bisogno di interrogare il mio DB per afferrare l'URL!

Voglio usarlo con reverse().


11
A parte questo: il modulo siti colpisce solo il DB la prima volta che ha bisogno del nome del sito, il risultato viene memorizzato nella cache in una variabile del modulo (SITE_CACHE) che rimarrà fino alla ricompilazione del modulo o SiteManager.clear_cache () viene chiamato metodo. Vedi: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Colonnello Sponsz

Risposte:


513

Usa il pratico metodo request.build_absolute_uri () su richiesta, passagli l'URL relativo e te ne darà uno completo.

Per impostazione predefinita, request.get_full_path()viene restituito l' URL assoluto per , ma è possibile passargli un URL relativo come primo argomento per convertirlo in un URL assoluto.


3
Che dire dell'URL: localhost / home / # / test ? Vedo solo localhost / home . Come posso vedere la parte dopo la nitidezza ?
sergzach,

41
tutto dopo che # non viene passato al server, è solo funzione del browser
Dmitry Shevchenko,

70
In un modello (dove non puoi fornire parametri) puoi semplicemente fare questo: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- e heyho, url completo.
odinho - Velmont,

17
E se non avessi accesso alla richiesta? Come nei serializzatori di Django-REST-Framework?
minder,

15
Ho dovuto usarlo {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}perché {{ request.build_absolute_uri }}aveva una barra finale e ho {{ object.get_absolute_url }}iniziato con una barra con conseguente doppia barra nell'URL.
Xtranophilist,

97

Se vuoi usarlo con reverse()puoi farlo:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
Grazie per la risposta utile Niente di meglio del codice stesso. (inoltre, probabilmente intendevi url_nameinvece di view_name)
Anupam

3
@Anupam reverse () è definito come:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

È inoltre possibile utilizzare get_current_sitecome parte dell'app dei siti ( from django.contrib.sites.models import get_current_site). Prende un oggetto richiesta e, per impostazione predefinita, SITE_IDviene impostato l'oggetto sito configurato in settings.py, se richiesto None. Maggiori informazioni nella documentazione per l' utilizzo del framework dei siti

per esempio

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

Non è compatto / pulito come request.build_absolute_url(), ma è utilizzabile quando gli oggetti richiesta non sono disponibili e hai un URL del sito predefinito.


4
Credo che la mia domanda abbia detto specificamente "senza il modulo Sites". Questo colpisce il DB?
Aprire l'

1
Il modulo Sites è stato scritto per memorizzare nella cache gli oggetti del sito utilizzando la memorizzazione nella cache a livello di modulo (ovvero non è necessario il framework della cache), quindi il DB dovrebbe essere colpito solo la prima volta che un sito viene recuperato da un processo web. Se non lo hai django.contrib.sitesnel tuo INSTALLED_APPS, non colpirà affatto il DB e fornirà informazioni basate sull'oggetto Request (vedi get_current_site )
Darb

1
Bene, allora puoi avere un +1, ma build_absolute_urisembra comunque la soluzione più semplice e pulita.
Aprire il

1
Questa è una risposta perfetta se stai cercando di generare URL in segnali da cui inviare e-mail.
Chris,

2
Non funziona se si utilizza https. Sì, potresti aggiungere la s, ma sviluppi con https localmente? e sai sempre, se hai https ma non a volte ...?
tjati,

55

Se non riesci ad accedere, requestnon puoi utilizzare get_current_site(request)come raccomandato in alcune soluzioni qui. È invece possibile utilizzare una combinazione del framework dei siti nativo get_absolute_url. Imposta almeno un sito nell'amministratore, assicurati che il tuo modello abbia un nell'amministratore metodo get_absolute_url () , quindi:

>>> 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


7
Questo è molto utile quando non si ha accesso all'oggetto HttpRequest. ad es. in compiti, segnali, ecc.
Arsham,

6
prima di usarlo dovresti abilitare il framework dei siti docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan,

Per cambiare esempio.com in qualcosa anche: Site.objects.all () [0] restituisce 'esempio.com' e ha id = 1, che è stato specificato in settings.py. Basta fare Site.objects.create (name = 'production', domain = 'prodsite.com') e impostare SITE_ID = 2 in settings.py. Ora Site.objects.get_current (). Domain restituisce 'prodsite.com'.
gek,

È possibile impostare requesta Noneo chiamare get_current_site(None).
Bobort,

20

Se non si desidera colpire il database, è possibile farlo con un'impostazione. Quindi, utilizzare un processore di contesto per aggiungerlo a ogni modello:

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

17

A tuo avviso, fai solo questo:

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

14

django-fullurl

Se stai cercando di farlo in un modello Django, ho rilasciato un piccolo pacchetto PyPI django-fullurlper permetterti di sostituire urle statictag modello con fullurle fullstatic, in questo modo:

{% load fullurl %}

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

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

Si spera che questi badge rimangano aggiornati automaticamente:

PyPI Travis CI

In una vista, puoi ovviamente usare request.build_absolute_uriinvece.


Peccato che non funziona con 2.0. Potrebbe essere necessario aumentare un PR.
Steven Church,

@StevenChurch Dovrebbe funzionare. Non ho ancora contrassegnato Django 2.0 come supportato, ma la versione esistente dovrebbe funzionare.
Flimm,

Per le mie esigenze ho risolto il problema passando un ENV da Heroku per il failback. Il mio problema è far passare l'URL ai modelli di email. Non ricordo il problema, ma non ha funzionato a causa di una modifica di Django.
Steven Church,

@StevenChurch Penso che il problema durante la creazione di e-mail sia che non esiste alcun requestoggetto per ottenere il nome di dominio. In tal caso, è necessario utilizzare sitesinvece il framework, che ottiene il nome di dominio dal database. Vedi django-absoluteuri, menzionato nella sezione "vedi anche" del README di questo pacchetto PyPI.
Flimm,

8

Per creare un collegamento completo a un'altra pagina da un modello, è possibile utilizzare questo:

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

request.META.HTTP_HOST fornisce il nome host e url fornisce il nome relativo. Il motore modello quindi li concatena in un URL completo.


2
Alla risposta manca il protocollo ( httpin questo contesto) e ://parte dell'URL, quindi non fornirà un URL completo .
user272735

2
L'oggetto richiesta ha un host su di esso. Non esaminare meta direttamente: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde,

8

Ancora un altro modo. Puoi usarlo build_absolute_uri()nel tuo view.pye passarlo al modello.

view.py

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

your-template.html

{{ baseurl }}

HttpRequest.build_absolute_uri(request)è equivalente a request.build_absolute_uri()non è vero?
Aprire il


7

Prova il seguente codice:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}

Questo darà il dominio senza il percorso e la stringa di query, no?
mpen

6

Questo ha funzionato per me nel mio modello:

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

Avevo bisogno dell'URL completo per passarlo a una funzione di recupero js. Spero che questo ti sia d'aiuto.


5

So che questa è una vecchia domanda. Ma penso che la gente si imbatta ancora molto in questo.

Ci sono un paio di librerie là fuori che integrano la funzionalità predefinita di Django. Ne ho provati alcuni. Mi piace la seguente libreria quando si fa riferimento inverso a URL assoluti:

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

Un altro che mi piace perché puoi facilmente mettere insieme un dominio, un protocollo e un percorso è:

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

Questa libreria consente di scrivere semplicemente ciò che si desidera nel modello, ad esempio:

{{url_parts.domain}}

4

Se si utilizza il framework REST di django, è possibile utilizzare la funzione inversa da rest_framework.reverse. Questo ha lo stesso comportamento di django.core.urlresolvers.reverse, tranne per il fatto che utilizza un parametro di richiesta per creare un 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,))

Modificato per menzionare la disponibilità solo nel framework REST


Viene visualizzato un errore durante l'utilizzo request=request. Inoltre, non sembra che la richiesta sia documentata qui docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos,

Ho dimenticato di menzionare che è disponibile solo se si utilizza il framework REST. Buona cattura, ho aggiornato la mia risposta.
JohnG,

Sì, grazie - funziona come un incantesimo con il framework REST di django
Apoorv Kansal,

1

Capito:

wsgiref.util.request_uri(request.META)

Ottieni l'uri completo con schema, host, percorso della porta e query.


0

Vi è anche ABSOLUTE_URL_OVERRIDES disponibile come impostazione

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

Ma questo sostituisce get_absolute_url (), che potrebbe non essere desiderabile.

Invece di installare framework di siti solo per questo o fare alcune delle altre cose menzionate qui che si basano sull'oggetto richiesta, penso che la soluzione migliore sia quella di collocare questo in models.py

Definisci BASE_URL in settings.py, quindi importalo in models.py e crea una classe astratta (o aggiungila a quella che stai già utilizzando) che definisce get_truly_absolute_url (). Potrebbe essere semplice come:

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

Sottoclassalo e ora puoi usarlo ovunque.


0

Come menzionato in altre risposte, request.build_absolute_uri()è perfetto se si ha accesso a request, esites framework è eccezionale fintanto che URL diversi puntano a database diversi.

Tuttavia, il mio caso d'uso era leggermente diverso. Il mio server di gestione temporanea e il server di produzione accedono allo stesso database, ma get_current_siteentrambi hanno restituito il primo sitenel database. Per risolvere questo problema, devi utilizzare un qualche tipo di variabile d'ambiente. Puoi usare 1) una variabile d'ambiente (qualcosa del genere os.environ.get('SITE_URL', 'localhost:8000')) o 2) SITE_IDs differenti per server diversi E settings.py diversi .

Eventualmente qualcuno lo troverà utile!


0

Mi sono imbattuto in questo thread perché stavo cercando di creare un URI assoluto per una pagina di successo. request.build_absolute_uri()mi ha dato un URI per la mia vista corrente ma per ottenere l'URI per la mia vista di successo ho usato il seguente ...

request.build_absolute_uri (inversa ( 'success_view_name'))



-5

Puoi anche usare:

import socket
socket.gethostname()

Questo funziona bene per me,

Non sono del tutto sicuro di come funzioni. Credo che questo sia un po 'più basso livello e restituirà il nome host del server, che potrebbe essere diverso dal nome host utilizzato dall'utente per accedere alla tua pagina.


Sì ... hai sottolineato il problema. Il nome host non è necessariamente uguale al nome dominio.
mpen

Questo risolve un problema molto diverso. Prendi in considerazione un server di hosting condiviso con più siti Web: utilizzando il codice sopra, tutti i siti che generano URL avranno tutti questi URL che puntano al computer host, che probabilmente NON è uno dei siti Web in esecuzione.
TB

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.