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().

Mpen
sumber
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.

Dmitry Shevchenko
sumber
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, )))

ébewè
sumber
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.

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

shacker
sumber
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>
seddonym
sumber
17

Menurut Anda, lakukan saja ini:

base_url =  "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
pungutan
sumber
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.

Flimm
sumber
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.

Doug Bradshaw
sumber
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 }}
Sven Rojek
sumber
HttpRequest.build_absolute_uri(request)setara dengan request.build_absolute_uri()bukan?
mpen
7

Periksa Request.METAkamus yang masuk. Saya pikir itu memiliki nama server dan port server.

Kugel
sumber
2
gunakan request.META ['HTTP_HOST']
Antony
4
Objek permintaan memiliki host di dalamnya. Jangan memeriksa meta secara langsung: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde
7

Coba kode berikut:

{{ request.scheme }}://{{ request.META.HTTP_HOST }}
menandai
sumber
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.

Jose Luis Quichimbo
sumber
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}}
johniak20
sumber
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

JohnG
sumber
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.

bertanya-tanya
sumber
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.

aris
sumber
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!

Bartleby
sumber
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'))

Soundtemple
sumber
-2

request.get_host() akan memberi Anda domain.

Roge
sumber
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.

Eduardo
sumber
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
-6

Anda dapat mencoba "request.get_full_path ()"

Max Ferreira
sumber
3
Ini tidak termasuk domain.
TAH