Comment puis-je obtenir l'URL complète / absolue (avec domaine) dans Django?

379

Comment puis-je obtenir l'URL complète / absolue (par exemple https://example.com/some/path) dans Django sans le module Sites ? C'est juste idiot ... Je ne devrais pas avoir besoin d'interroger ma base de données pour accrocher l'URL!

Je veux l'utiliser avec reverse().

mpen
la source
11
En passant: le module sites ne frappe la base de données que la première fois qu'il a besoin du nom du site, le résultat est mis en cache dans une variable de module (SITE_CACHE) qui restera jusqu'à la recompilation du module ou du SiteManager.clear_cache () est appelée. Voir: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Colonel Sponsz

Réponses:

513

Utilisez la méthode request.build_absolute_uri () pratique sur demande, passez-lui l'URL relative et elle vous en donnera une complète.

Par défaut, l'URL absolue de request.get_full_path()est renvoyée, mais vous pouvez lui passer une URL relative comme premier argument pour la convertir en URL absolue.

Dmitry Shevchenko
la source
3
Qu'en est-il de l'URL: localhost / home / # / test ? Je ne peux voir que localhost / home . Comment puis-je voir la pièce après la netteté ?
sergzach
41
tout après que # ne soit pas transmis au serveur, c'est une fonctionnalité uniquement pour navigateur
Dmitry Shevchenko
70
Dans un modèle (où vous ne pouvez pas donner de paramètres), vous pouvez simplement faire ceci: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- et heyho, URL complète.
odinho - Velmont
17
Et si je n'ai pas accès à la demande? Comme dans les sérialiseurs de Django-REST-Framework?
gardien
15
J'ai dû utiliser {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}car il y {{ request.build_absolute_uri }}avait une barre oblique de fin et j'ai {{ object.get_absolute_url }}commencé avec une barre oblique entraînant des doubles barres obliques dans l'URL.
xtranophilist
97

Si vous souhaitez l'utiliser avec reverse()vous pouvez le faire:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))

ébewè
la source
3
Merci pour la réponse utile. Rien de mieux que le code lui-même. (aussi, vous vouliez probablement dire url_nameau lieu de view_name)
Anupam
3
@Anupam reverse () est défini comme suit:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart
57

Vous pouvez également l'utiliser get_current_sitedans le cadre de l'application sites ( from django.contrib.sites.models import get_current_site). Il prend un objet de demande et prend par défaut l'objet de site avec lequel vous avez configuré SITE_IDdans settings.py si la demande l'est None. En savoir plus dans la documentation pour utiliser le framework de sites

par exemple

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

Il n'est pas aussi compact / soigné que request.build_absolute_url(), mais il est utilisable lorsque les objets de demande ne sont pas disponibles et que vous avez une URL de site par défaut.

Darb
la source
4
Je crois que ma question disait spécifiquement "sans le module Sites". Est-ce que cela a touché la DB?
mpen
1
Le module Sites a été écrit pour mettre en cache les objets Site à l'aide de la mise en cache au niveau du module (c'est-à-dire que vous n'avez pas besoin de la structure de cache), de sorte que la base de données ne doit être atteinte que la première fois qu'un site est récupéré par un processus Web. Si vous n'avez pas django.contrib.sitesdans votre INSTALLED_APPS, il ne touche pas le DB du tout, et de fournir des informations basées sur l'objet de la demande (voir get_current_site )
Darb
1
Eh bien, vous pouvez avoir un +1, mais cela build_absolute_urisemble toujours la solution la plus simple et la plus propre.
mpen
1
C'est une réponse parfaite si vous essayez de générer des URL dans des signaux à partir desquels envoyer des e-mails.
Chris
2
Ne fonctionne pas si vous utilisez https. Oui, vous pouvez ajouter le s, mais développez-vous localement avec https? et savez-vous toujours, si vous avez https mais pas parfois ...?
tjati
55

Si vous ne pouvez pas y accéder, requestvous ne pouvez pas l'utiliser get_current_site(request)comme recommandé dans certaines solutions ici. Vous pouvez utiliser une combinaison du framework Sites natif et à la get_absolute_urlplace. Configurez au moins un site dans l'administrateur, assurez-vous que votre modèle dispose d'une méthode get_absolute_url () , puis:

>>> 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
la source
7
C'est vraiment pratique lorsque vous n'avez pas accès à l'objet HttpRequest. par exemple dans les tâches, les signaux, etc.
Arsham
6
avant de l'utiliser, vous devez activer le framework de sites docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan
Pour changer example.com en quelque chose aussi: Site.objects.all () [0] renvoie 'example.com' et a id = 1, qui a spécifié dans settings.py. Faites simplement Site.objects.create (name = 'production', domain = 'prodsite.com') et définissez SITE_ID = 2 dans settings.py. Maintenant, Site.objects.get_current (). Domain renvoie 'prodsite.com'.
gek
Vous pouvez définir requestà Noneou appel get_current_site(None).
Bobort
20

Si vous ne voulez pas accéder à la base de données, vous pouvez le faire avec un paramètre. Ensuite, utilisez un processeur de contexte pour l'ajouter à chaque modèle:

# 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
la source
17

À votre avis, procédez comme suit:

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

django-fullurl

Si vous essayez de le faire dans un modèle Django, j'ai publié un petit paquet PyPI django-fullurlpour vous permettre de remplacer urlet de staticbalises de modèle avec fullurlet fullstatic, comme ceci:

{% load fullurl %}

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

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

Nous espérons que ces badges resteront à jour automatiquement:

PyPI Travis CI

Dans une vue, vous pouvez bien sûr utiliser à la request.build_absolute_uriplace.

Flimm
la source
Dommage que cela ne fonctionne pas avec 2.0. Pourrait avoir besoin de pousser un PR.
Steven Church
@StevenChurch Cela devrait fonctionner. Je n'ai pas encore marqué Django 2.0 comme supporté, mais la version existante devrait fonctionner.
Flimm
Pour mes besoins, j'ai contourné cela en passant un ENV de Heroku pour le rétablissement. Mon problème est de faire passer l'URL aux modèles de courrier électronique. Je ne me souviens pas du problème mais cela n'a pas fonctionné en raison d'un changement de Django.
Steven Church
@StevenChurch Je pense que le problème lors de la création de courriels est qu'il n'y a aucun requestobjet pour obtenir le nom de domaine. Dans ce cas, vous devez utiliser le sitesframework à la place, qui obtient le nom de domaine de la base de données. Voir django-absoluteuri, mentionné dans la section "voir aussi" du fichier README de ce package PyPI.
Flimm
8

Pour créer un lien complet vers une autre page à partir d'un modèle, vous pouvez utiliser ceci:

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

request.META.HTTP_HOST donne le nom d'hôte et url le nom relatif. Le moteur de modèle les concatène ensuite en une URL complète.

Doug Bradshaw
la source
2
La réponse manque le protocole ( httpdans ce contexte) et une ://partie de l'URL, donc il ne fournira pas une URL complète .
user272735
2
L'objet de demande contient un hôte. N'examinez
Kit Sunde
8

Encore une autre façon. Vous pouvez l'utiliser build_absolute_uri()dans votre view.pyet le transmettre au modèle.

view.py

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

votre-template.html

{{ baseurl }}
Sven Rojek
la source
HttpRequest.build_absolute_uri(request)est équivalent à request.build_absolute_uri()non?
mpen
7

Examinez le Request.METAdictionnaire qui entre. Je pense qu'il a un nom de serveur et un port de serveur.

Kugel
la source
2
use request.META ['HTTP_HOST']
Antony
4
L'objet de demande contient un hôte. N'examinez
Kit Sunde
7

Essayez le code suivant:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}
marque
la source
Cela donnera simplement le domaine sans le chemin et la chaîne de requête, non?
mpen
6

Cela a fonctionné pour moi dans mon modèle:

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

J'avais besoin de l'url complète pour la transmettre à une fonction js fetch. J'espère que cela vous aidera.

Jose Luis Quichimbo
la source
5

Je sais que c'est une vieille question. Mais je pense que les gens se heurtent encore beaucoup à cela.

Il existe quelques bibliothèques qui complètent la fonctionnalité Django par défaut. J'en ai essayé quelques-uns. J'aime la bibliothèque suivante lors du référencement inverse des URL absolues:

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

Un autre que j'aime parce que vous pouvez facilement mettre en place un domaine, un protocole et un chemin est:

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

Cette bibliothèque vous permet d'écrire simplement ce que vous voulez dans votre modèle, par exemple:

{{url_parts.domain}}
johniak20
la source
4

Si vous utilisez le framework django REST, vous pouvez utiliser la fonction inverse de rest_framework.reverse. Cela a le même comportement que django.core.urlresolvers.reverse, sauf qu'il utilise un paramètre de demande pour créer une URL complète.

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

Modifié pour mentionner la disponibilité uniquement dans le cadre REST

JohnG
la source
Je reçois une erreur en utilisant request=request. Il ne semble pas non plus que la demande soit documentée ici docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos
J'ai oublié de mentionner que cela n'est disponible que si vous utilisez le framework REST. Bonne prise, j'ai mis à jour ma réponse.
JohnG
Oui merci - cela fonctionne comme un charme avec le framework django REST
Apoorv Kansal
1

J? ai compris:

wsgiref.util.request_uri(request.META)

Obtenez l'URI complet avec le schéma, l'hôte, le chemin du port et la requête.

merveille
la source
0

Il existe également ABSOLUTE_URL_OVERRIDES comme paramètre

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

Mais cela remplace get_absolute_url (), ce qui n'est peut-être pas souhaitable.

Au lieu d'installer le framework de sites juste pour cela ou de faire certaines des autres choses mentionnées ici qui reposent sur un objet de demande, je pense que la meilleure solution est de le placer dans models.py

Définissez BASE_URL dans settings.py, puis importez-le dans models.py et créez une classe abstraite (ou ajoutez-la à celle que vous utilisez déjà) qui définit get_truly_absolute_url (). Cela pourrait être aussi simple que:

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

Sous-classe et maintenant vous pouvez l'utiliser partout.

aris
la source
0

Comme mentionné dans d'autres réponses, request.build_absolute_uri()est parfait si vous y avez accès requestet le sitescadre est excellent tant que différentes URL pointent vers différentes bases de données.

Cependant, mon cas d'utilisation était légèrement différent. Mon serveur de transfert et le serveur de production accèdent à la même base de données, mais get_current_sitetous deux ont renvoyé le premier sitedans la base de données. Pour résoudre ce problème, vous devez utiliser une sorte de variable d'environnement. Vous pouvez soit utiliser 1) une variable d'environnement (quelque chose comme os.environ.get('SITE_URL', 'localhost:8000')) ou 2) différents SITE_IDs pour différents serveurs ET différents settings.py .

J'espère que quelqu'un trouvera cela utile!

Bartleby
la source
0

Je suis tombé sur ce fil parce que je cherchais à créer un URI absolu pour une page de réussite. request.build_absolute_uri()m'a donné un URI pour ma vue actuelle, mais pour obtenir l'URI de ma vue de réussite, j'ai utilisé ce qui suit ....

request.build_absolute_uri (reverse ('success_view_name'))

Soundtemple
la source
-2

request.get_host() vous donnera le domaine.

Roge
la source
1
La question indique, URL complète
acidjunk
-5

Vous pouvez aussi utiliser:

import socket
socket.gethostname()

Cela fonctionne bien pour moi,

Je ne sais pas trop comment cela fonctionne. Je crois que c'est un peu plus bas et retournera le nom d'hôte de votre serveur, qui pourrait être différent du nom d'hôte utilisé par votre utilisateur pour accéder à votre page.

Eduardo
la source
Ouais ... tu as signalé le problème. Le nom d'hôte n'est pas nécessairement le même que le nom de domaine.
mpen
Cela résout un problème très différent. Considérez un serveur d'hébergement partagé avec plusieurs sites Web - en utilisant le code ci-dessus, tous les sites générant des URL auront toutes ces URL pointant vers la machine hôte, qui n'est probablement PAS l'un des sites Web en cours d'exécution.
tbm
-6

Vous pouvez essayer "request.get_full_path ()"

Max Ferreira
la source
3
Cela n'inclut pas le domaine.
TAH