Django'da tam / mutlak URL'yi (alan adıyla) nasıl edinebilirim?


379

Sites modülü olmadanhttps://example.com/some/path Django'daki tam / mutlak URL'yi (ör. ) Nasıl edinebilirim ? Bu sadece aptalca ... URL'yi takmak için DB'mi sorgulamam gerekmiyor!

İle kullanmak istiyorum reverse().


11
Bir kenara olduğu gibi: Siteler modülü DB'ye yalnızca site adına ilk kez ihtiyaç duyduğunda vurur, sonuç modülün veya SiteManager.clear_cache () yeniden derleninceye kadar değişecek bir modül değişkeninde (SITE_CACHE) önbelleğe alınır. yöntemi denir. Bkz. Code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Albay Sponsz

Yanıtlar:


512

Talep üzerine kullanışlı request.build_absolute_uri () yöntemini kullanın , göreli URL'yi iletin ve size tam bir URL verecektir.

Varsayılan olarak, için mutlak URL request.get_full_path()döndürülür, ancak onu mutlak bir URL'ye dönüştürmek için ilk bağımsız değişken olarak göreli bir URL iletebilirsiniz.


3
URL ne olacak: localhost / home / # / test ? Sadece localhost / home'u görebiliyorum . Nasıl sonra parçası görebilirsiniz keskin ?
sergzach

41
# 'den sonra her şey sunucuya geçmez, sadece tarayıcı özelliği
Dmitry Shevchenko

70
Bir şablonda (parametre veremediğiniz yerde) bunu yapabilirsiniz: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- ve heyho, tam url.
odinho - Velmont

17
Ya talebe erişimim yoksa? Django-REST-Framework'ün Serileştiricileri gibi mi?
minder

15
Kullanmak zorundaydım {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}çünkü bir eğik çizgi vardı ve URL'de çift eğik çizgi ile sonuçlanan bir eğik {{ request.build_absolute_uri }}çizgi ile {{ object.get_absolute_url }}başladı.
xtranophilist

96

Birlikte kullanmak reverse()istiyorsanız bunu yapabilirsiniz:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
Yararlı cevap için teşekkürler. Kodun kendisinden daha iyi bir şey yok. (ayrıca, muhtemelen url_namebunun yerine demek view_name
Anupam

3
@Anupam reverse () şu şekilde tanımlanır:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

Ayrıca get_current_sitesiteler uygulamasının ( from django.contrib.sites.models import get_current_site) bir parçası olarak da kullanabilirsiniz . Bir istek nesnesi alır ve istek SITE_IDvarsa, settings.py içinde yapılandırdığınız site nesnesini varsayılan olarak kullanır None. Site çerçevesini kullanma ile ilgili belgelerde daha fazla bilgi edinin

Örneğin

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

Oldukça kompakt / düzenli değil request.build_absolute_url(), ancak istek nesneleri kullanılamadığında kullanılabilir ve varsayılan bir site URL'niz var.


4
Sorumun özellikle "Sites modülü olmadan" dediğine inanıyorum. Bu DB vurur mu?
mpen

1
Sites modülü, modül düzeyinde önbellekleme kullanarak Site nesnelerini önbelleğe yazmak için yazılmıştır (yani önbellek çerçevesine ihtiyacınız yoktur), bu nedenle DB yalnızca bir Site bir web işlemi tarafından ilk kez alındığında kullanılmalıdır. Eğer yoksa django.contrib.sitesGözlerinde farklı INSTALLED_APPS, hiç DB vurmak olmaz ve (bkz Request nesnesi dayalı bilgi vermek get_current_site )
Darb

1
Peki + 1'iniz olabilir, ancak build_absolute_uriyine de daha kolay ve daha temiz bir çözüm gibi görünüyor.
mpen

1
E-posta gönderilecek sinyallerde URL'ler oluşturmaya çalışıyorsanız bu mükemmel bir yanıttır.
Chris

2
Https kullanırsanız çalışmaz. Evet, s'yi ekleyebilirsiniz, ancak yerel olarak https ile gelişiyor musunuz? Ve her zaman biliyor musun, eğer https'niz varsa ama bazen değil ...?
tjati

55

Erişim requestsağlayamıyorsanız get_current_site(request), buradaki bazı çözümlerde önerildiği gibi kullanamazsınız . Yerel Sites çerçevesinin bir kombinasyonunu ve get_absolute_urlbunun yerine kullanabilirsiniz. Yönetici içinde en az bir Site oluşturun , modelinizde bir get_absolute_url () yöntemi bulunduğundan emin olun , ardından:

>>> 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
Bu, HttpRequest nesnesine erişiminiz olmadığında gerçekten kullanışlıdır. örneğin görevlerde, sinyallerde vb.
Arsham


Example.com'u başka bir şeyle değiştirmek için: Site.objects.all () [0] 'example.com' döndürür ve settings.py'de belirtilen id = 1 değerine sahiptir. Sadece Site.objects.create (name = 'production', domain = 'prodsite.com') yapın ve settings.py'de SITE_ID = 2 ayarını yapın. Şimdi Site.objects.get_current (). Alan adı 'prodsite.com' döndürüyor.
1919'da

Ayarlayabilirsiniz requestiçin Noneveya çağrı get_current_site(None).
Bobort

20

Veritabanına vurmak istemiyorsanız, bunu bir ayarla yapabilirsiniz. Ardından, her şablona eklemek için bir bağlam işlemcisi kullanın:

# 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

Sizce şunu yapın:

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

14

django-fullurl

Bir Django şablonunda bunu çalışıyorsanız, ben küçücük PyPI paketi sunduk django-fullurlDeğiştirmek izin urlve staticşablon etiketleri fullurlve fullstaticbunun gibi,:

{% load fullurl %}

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

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

Bu rozetler umarım otomatik olarak güncel kalmalıdır:

PyPI Travis CI

Bir görünümde, elbette request.build_absolute_uribunun yerine kullanabilirsiniz .


Yazık ki bu 2.0 ile çalışmaz. Bir PR'yi yükseltmek gerekebilir.
Steven Kilisesi

@StevenChurch Çalışmalı. Django 2.0'ı henüz desteklenen olarak işaretlemedim, ancak mevcut sürümün çalışması gerekiyor.
Flimm

İhtiyaçlarım için Heroku'dan başarısızlık için bir ENV geçirerek bunu tamamladım. Sorunum, URL'nin e-posta şablonlarına geçmesini sağlamak. Sorunu hatırlayamıyorum ama bir Django değişikliği nedeniyle işe yaramadı.
Steven Church

@StevenChurch E-posta oluştururken sorun request, alan adını almak için hiçbir nesne olmamasıdır. Bu durumda, sitesetki alanını veritabanından alan çerçeveyi kullanmalısınız. Bkz django-absoluteuri. Bu PyPI paketinin README'sinin "ayrıca bkz." Bölümünde.
Flimm

8

Bir şablondan başka bir sayfaya eksiksiz bir bağlantı oluşturmak için şunu kullanabilirsiniz:

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

request.META.HTTP_HOST ana bilgisayar adını ve url göreli adı verir. Şablon motoru daha sonra bunları tam bir URL'ye birleştirir.


2
Yanıtta protokol ( httpbu bağlamda) ve ://URL'nin bir kısmı eksik olduğundan tam bir URL sağlamayacak .
user272735

2
İstek nesnesinin üzerinde bir ana bilgisayar var. Metaları
Kit Sunde

8

Yine başka bir yol. Kullanabilirsinbuild_absolute_uri() Gözlerinde farklı view.pyve şablona geçmek.

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)eşittir request.build_absolute_uri()değil mi?
mpen

7

Gelen Request.METAsözlüğü inceleyin . Bence sunucu adı ve sunucu portu var.


2
request.META ['HTTP_HOST'] kullanın
Antony

4
İstek nesnesinin üzerinde bir ana bilgisayar var. Metaları
Kit Sunde

7

Aşağıdaki kodu deneyin:

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

Bu sadece etki alanı yol ve sorgu dizesi olmadan verir, değil mi?
mpen

6

Şablonumda bu benim için çalıştı:

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

Bir js getirme işlevine geçmek için tam url gerekli. Umarım bu sana yardımcı olur.


5

Bunun eski bir soru olduğunu biliyorum. Ama bence insanlar hala bununla çok uğraşıyorlar.

Varsayılan Django işlevselliğini destekleyen birkaç kütüphane var. Birkaçını denedim. Mutlak URL'leri tersine çevirirken aşağıdaki kütüphaneyi beğendim:

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

Bir etki alanı, protokol ve yolu kolayca bir araya getirebileceğiniz için sevdiğim başka bir tane:

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

Bu kütüphane, şablonunuzda istediğinizi yazmanıza olanak tanır, örneğin:

{{url_parts.domain}}

4

Django REST çerçevesini kullanıyorsanız, adresinden reverse işlevini kullanabilirsiniz rest_framework.reverse. django.core.urlresolvers.reverseTam URL oluşturmak için bir istek parametresi kullanması dışında, bunun davranışıyla aynıdır .

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

Yalnızca REST çerçevesinde kullanılabilirlikten bahsetmek için düzenlendi


Kullanarak bir hata alıyorum request=request. Ayrıca, istek burada belgelenmiş gibi görünmüyor docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos

Bunun yalnızca REST çerçevesini kullanıyorsanız mevcut olduğunu belirtmeyi unuttum. İyi yakaladım, cevabımı güncelledim.
JohnG

Evet teşekkür ederim - django REST framework
Apoorv Kansal

1

Anladım:

wsgiref.util.request_uri(request.META)

Şema, ana bilgisayar, bağlantı noktası yolu ve sorgu ile tam uri alın.


0

Ayrıca ayar olarak ABSOLUTE_URL_OVERRIDES kullanılabilir

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

Ancak bu, istenmeyebilecek get_absolute_url () yöntemini geçersiz kılar.

Siteler çerçevesini sadece bunun için yüklemek veya burada belirtilen istek nesnesine dayanan diğer bazı şeyleri yapmak yerine, bence daha iyi bir çözüm bunu models.py'ye yerleştirmektir.

Settings.py'de BASE_URL tanımlayın, ardından models.py dosyasına aktarın ve get_truly_absolute_url () öğesini tanımlayan soyut bir sınıf yapın (veya zaten kullanmakta olduğunuz bir tanesine ekleyin). Bu kadar basit olabilir:

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

Alt sınıflandırın ve şimdi her yerde kullanabilirsiniz.


0

Diğer cevaplarda belirtildiği gibi request.build_absolute_uri(), erişiminiz varsa requestvesites farklı URL'ler farklı veritabanlarına işaret ettiği sürece çerçeve harikadır.

Ancak benim kullanım durumum biraz farklıydı. Evreleme sunucum ve üretim sunucum aynı veritabanına erişiyor, ancak get_current_siteher ikisi sitede veritabanındaki ilk veritabanını döndürdü . Bu sorunu çözmek için bir tür ortam değişkeni kullanmanız gerekir. Farklı sunucular VE farklı ayarlar için 1) bir ortam değişkeni (bir şey gibi os.environ.get('SITE_URL', 'localhost:8000')) veya 2) farklı SITE_IDs kullanabilirsiniz .

Umarım birisi bunu faydalı bulacaktır!


0

Ben bir başarı sayfası için mutlak bir URI oluşturmak için bakıyordu çünkü bu iş parçacığı geldi. request.build_absolute_uri()bana şimdiki görüşüm için bir URI verdi ama başarı görünümüm için URI almak için aşağıdakileri kullandım ....

request.build_absolute_uri (ters ( 'success_view_name'))


-2

request.get_host() size etki alanını verecektir.


1
Soru devletler, tam URL
acidjunk

-5

Ayrıca kullanabilirsiniz:

import socket
socket.gethostname()

Bu benim için iyi çalışıyor,

Nasıl çalıştığından tam olarak emin değilim. Bunun biraz daha düşük bir düzey olduğuna ve sayfanıza ulaşmak için kullanıcı tarafından kullanılan ana makine adından farklı olabilecek sunucu ana makine adınızı döndüreceğine inanıyorum.


Evet ... soruna dikkat çektin. Ana bilgisayar adı, alan adıyla aynı olmak zorunda değildir.
mpen

Bu çok farklı bir sorunu çözer. Birden fazla web sitesine sahip paylaşılan bir barındırma sunucusunu düşünün - yukarıdaki kodu kullanarak, URL üreten tüm sitelerde ana bilgisayar makinesine işaret eden tüm bu URL'ler bulunur; bu, çalışan web sitelerinin hiçbiri DEĞİLDİR.
tbm

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.