Bagaimana saya bisa mendapatkan URL penuh / absolut (dengan domain) di Django?


379

Bagaimana saya bisa mendapatkan URL penuh / absolut (misalnya https://example.com/some/path) di Django tanpa modul Situs ? Itu konyol ... Saya tidak perlu meminta DB saya untuk mengambil URL!

Saya ingin menggunakannya reverse().


11
Selain itu: Modul situs hanya mengenai DB saat pertama kali membutuhkan nama situs, hasilnya di-cache dalam variabel modul (SITE_CACHE) yang akan bertahan sampai kompilasi ulang modul atau SiteManager.clear_cache () Metode ini disebut. Lihat: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
Kolonel Sponsz

Jawaban:


513

Gunakan metode request.build_absolute_uri () yang berguna berdasarkan permintaan, berikan url relatifnya dan itu akan memberi Anda satu penuh.

Secara default, URL absolut untuk request.get_full_path()dikembalikan, tetapi Anda dapat memberikan URL relatif sebagai argumen pertama untuk mengubahnya menjadi URL absolut.


3
Bagaimana dengan url: localhost / home / # / test ? Saya hanya dapat melihat localhost / home . Bagaimana saya bisa melihat bagian setelah tajam ?
sergzach

41
semuanya setelah # tidak diteruskan ke server, ini fitur khusus browser
Dmitry Shevchenko

70
Dalam templat (di mana Anda tidak dapat memberikan parameter) Anda bisa melakukan ini: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- dan hei, url lengkap.
odinho

17
Dan bagaimana jika saya tidak memiliki akses untuk meminta? Seperti dalam Serializers Django-REST-Framework?
minder

15
Saya harus menggunakan {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}karena {{ request.build_absolute_uri }}memiliki garis miring dan {{ object.get_absolute_url }}mulai dengan garis miring menghasilkan garis miring ganda di URL.
xtranophilist

97

Jika Anda ingin menggunakannya, reverse()Anda dapat melakukan ini:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
Terima kasih atas jawabannya. Tidak ada yang lebih baik daripada kode itu sendiri. (juga, Anda mungkin bermaksud url_namebukannya view_name)
Anupam

3
@Anupam terbalik () didefinisikan sebagai:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

Anda juga dapat menggunakan get_current_sitesebagai bagian dari aplikasi situs ( from django.contrib.sites.models import get_current_site). Dibutuhkan objek permintaan, dan default ke objek situs yang telah Anda konfigurasikan SITE_IDdi settings.py jika permintaan None. Baca lebih lanjut dalam dokumentasi untuk menggunakan kerangka kerja situs

misalnya

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

Ini tidak kompak / rapi request.build_absolute_url(), tetapi dapat digunakan ketika objek permintaan tidak tersedia, dan Anda memiliki url situs default.


4
Saya percaya pertanyaan saya secara khusus mengatakan "tanpa modul Situs". Apakah ini mengenai DB?
mpen

1
Modul Situs telah ditulis ke cache objek Situs menggunakan caching tingkat modul (yaitu Anda tidak memerlukan kerangka cache), sehingga DB hanya akan terkena ketika pertama kali Situs diambil oleh proses web. Jika Anda tidak memiliki django.contrib.sitesdi Anda INSTALLED_APPS, itu tidak akan memukul DB sama sekali, dan memberikan informasi berdasarkan objek Request (lihat get_current_site )
Darb

1
Baiklah Anda dapat memiliki +1, tetapi build_absolute_urimasih terlihat seperti solusi yang lebih mudah dan bersih.
mpen

1
Ini adalah jawaban yang sempurna jika Anda mencoba menghasilkan URL dalam sinyal untuk mengirim email.
Chris

2
Tidak berfungsi, jika Anda menggunakan https. Ya, Anda dapat menambahkan s, tetapi apakah Anda mengembangkan dengan https secara lokal? dan apakah Anda selalu tahu, jika Anda memiliki https tetapi tidak kadang-kadang ...?
tjati

55

Jika Anda tidak dapat mengakses requestmaka Anda tidak dapat menggunakan get_current_site(request)seperti yang disarankan dalam beberapa solusi di sini. Anda dapat menggunakan kombinasi kerangka Situs asli dan get_absolute_urlsebagai gantinya. Siapkan setidaknya satu Situs di admin, pastikan model Anda memiliki metode get_absolute_url () , lalu:

>>> 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
Ini sangat berguna ketika Anda tidak memiliki akses ke objek HttpRequest. misalnya dalam tugas, sinyal dll.
Arsham

6
sebelum menggunakan ini, Anda harus mengaktifkan framework situs docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan

Untuk mengubah example.com menjadi sesuatu juga: Site.objects.all () [0] mengembalikan 'example.com' dan memiliki id = 1, yang ditentukan dalam settings.py. Lakukan saja Site.objects.create (name = 'production', domain = 'prodsite.com') dan setel SITE_ID = 2 di settings.py. Sekarang Site.objects.get_current (). Domain mengembalikan 'prodsite.com'.
gek

Anda dapat mengatur requestke Noneatau panggilan get_current_site(None).
Bobort

20

Jika Anda tidak ingin membuka database, Anda bisa melakukannya dengan pengaturan. Kemudian, gunakan pengolah konteks untuk menambahkannya ke setiap templat:

# 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

Menurut Anda, lakukan saja ini:

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

14

django-fullurl

Jika Anda mencoba melakukan ini di templat Django, saya telah merilis paket PyPI kecil django-fullurluntuk memungkinkan Anda mengganti urldan statictemplat tag dengan fullurldan fullstatic, seperti ini:

{% load fullurl %}

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

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

Lencana-lencan ini semoga tetap diperbarui secara otomatis:

PyPI Travis CI

Dalam sebuah tampilan, Anda tentu saja dapat menggunakannya request.build_absolute_uri.


Malu ini tidak bekerja dengan 2.0. Mungkin perlu untuk mendorong PR.
Gereja Steven

@ SvenvenChurch Ini seharusnya bekerja. Saya belum menandai Django 2.0 sebagai didukung, tetapi versi yang ada harus berfungsi.
Flimm

Untuk kebutuhan saya, saya menyelesaikan ini dengan melewati ENV dari Heroku untuk kegagalan. Masalah saya adalah mendapatkan URL untuk diteruskan ke templat email. Saya tidak dapat mengingat masalahnya tetapi tidak berhasil karena perubahan Django.
Steven Church

@ SvenvenChurch Saya pikir masalah saat membuat email adalah bahwa tidak ada requestobjek untuk mendapatkan nama domain. Dalam hal ini, Anda harus menggunakan siteskerangka sebagai gantinya, yang mendapatkan nama domain dari database. Lihat django-absoluteuri, disebutkan di bagian "lihat juga" dari README dari paket PyPI ini.
Flimm

8

Untuk membuat tautan lengkap ke halaman lain dari templat, Anda dapat menggunakan ini:

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

request.META.HTTP_HOST memberikan nama host, dan url memberikan nama relatif. Mesin templat kemudian menggabungkannya menjadi url lengkap.


2
Jawabannya tidak memiliki protokol ( httpdalam konteks ini) dan ://bagian dari URL, sehingga tidak akan memberikan url lengkap .
user272735

2
Objek permintaan memiliki host di dalamnya. Jangan memeriksa meta secara langsung: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde

8

Namun cara lain. Anda bisa menggunakannya build_absolute_uri()di dalam view.pydan meneruskannya ke templat.

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)setara dengan request.build_absolute_uri()bukan?
mpen


7

Coba kode berikut:

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

Itu hanya akan memberikan domain tanpa jalur dan string kueri, bukan?
mpen

6

Ini berfungsi untuk saya di templat saya:

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

Saya membutuhkan url lengkap untuk meneruskannya ke fungsi js fetch. Saya harap ini membantu Anda.


5

Saya tahu ini adalah pertanyaan lama. Tapi saya pikir orang masih sering mengalami hal ini.

Ada beberapa perpustakaan di luar sana yang melengkapi fungsi Django default. Saya sudah mencoba beberapa. Saya suka perpustakaan berikut ketika membalikkan referensi URL absolut:

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

Satu lagi yang saya suka karena Anda dapat dengan mudah mengumpulkan domain, protokol, dan jalur:

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

Pustaka ini memungkinkan Anda untuk menuliskan apa yang Anda inginkan di templat, misalnya:

{{url_parts.domain}}

4

Jika Anda menggunakan kerangka kerja Django REST, Anda dapat menggunakan fungsi sebaliknya dari rest_framework.reverse. Ini memiliki perilaku yang sama dengan django.core.urlresolvers.reverse, kecuali bahwa ia menggunakan parameter permintaan untuk membangun URL lengkap.

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

Diedit untuk menyebutkan ketersediaan hanya dalam kerangka REST


Saya mendapatkan kesalahan saat menggunakan request=request. Itu juga tidak tampak seperti permintaan didokumentasikan di sini docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos

Saya lupa menyebutkan ini hanya tersedia jika Anda menggunakan kerangka REST. Bagus, saya sudah memperbarui jawaban saya.
JohnG

Ya terima kasih - ini berfungsi seperti pesona dengan kerangka kerja Django Djesto
Apoorv Kansal

1

Saya mendapatkannya:

wsgiref.util.request_uri(request.META)

Dapatkan uri lengkap dengan skema, host, jalur port, dan permintaan.


0

Ada juga ABSOLUTE_URL_OVERRIDES yang tersedia sebagai pengaturan

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

Tapi itu menimpa get_absolute_url (), yang mungkin tidak diinginkan.

Alih-alih menginstal kerangka situs hanya untuk ini atau melakukan beberapa hal lain yang disebutkan di sini yang bergantung pada objek permintaan, saya pikir solusi yang lebih baik adalah menempatkan ini di models.py

Tentukan BASE_URL di settings.py, lalu impor ke dalam models.py dan buat kelas abstrak (atau tambahkan ke yang sudah Anda gunakan) yang mendefinisikan get_truly_absolute_url (). Ini bisa sesederhana:

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

Subkelas dan sekarang Anda dapat menggunakannya di mana saja.


0

Seperti disebutkan dalam jawaban lain, request.build_absolute_uri()sangat cocok jika Anda memiliki akses ke request, dansites kerangka kerjanya bagus selama URL yang berbeda menunjuk ke database yang berbeda.

Namun, use case saya sedikit berbeda. Server pementasan saya dan server produksi mengakses database yang sama, tetapi get_current_sitekeduanya mengembalikan yang pertama sitedalam database. Untuk mengatasi ini, Anda harus menggunakan semacam variabel lingkungan. Anda dapat menggunakan 1) variabel lingkungan (seperti os.environ.get('SITE_URL', 'localhost:8000')) atau 2) berbeda SITE_IDuntuk server yang berbeda DAN pengaturan yang berbeda.py .

Semoga seseorang akan menemukan ini berguna!


0

Saya menemukan utas ini karena saya ingin membangun URI absolut untuk halaman sukses. request.build_absolute_uri()memberi saya URI untuk tampilan saya saat ini tetapi untuk mendapatkan URI untuk tampilan kesuksesan saya, saya menggunakan yang berikut ....

request.build_absolute_uri (membalikkan ('success_view_name'))


-2

request.get_host() akan memberi Anda domain.


1
Pertanyaannya menyatakan, URL lengkap
acidjunk

-5

Anda juga bisa menggunakan:

import socket
socket.gethostname()

Ini bekerja dengan baik untuk saya,

Saya tidak sepenuhnya yakin cara kerjanya. Saya percaya ini sedikit lebih rendah dan akan mengembalikan nama host server Anda, yang mungkin berbeda dari nama host yang digunakan oleh pengguna Anda untuk sampai ke halaman Anda.


Ya..kamu menunjukkan masalahnya. Nama host belum tentu sama dengan nama domain.
mpen

Ini memecahkan masalah yang sangat berbeda. Pertimbangkan server hosting bersama dengan beberapa situs web - menggunakan kode di atas, semua situs yang menghasilkan URL akan memiliki semua URL yang menunjuk ke mesin host, yang kemungkinan BUKAN salah satu situs web yang berjalan.
tbm

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.