Làm cách nào tôi có thể nhận được URL đầy đủ / tuyệt đối (có tên miền) trong Django?


379

Làm cách nào tôi có thể nhận được URL đầy đủ / tuyệt đối (ví dụ https://example.com/some/path) trong Django mà không cần mô-đun Trang web ? Điều đó thật ngớ ngẩn ... Tôi không cần phải truy vấn DB của mình để lấy URL!

Tôi muốn sử dụng nó với reverse().


11
Chỉ là một bên: Mô-đun trang web chỉ chạm vào DB khi lần đầu tiên nó cần tên trang web, kết quả được lưu trong bộ biến mô-đun (SITE_CACHE) sẽ được giữ xung quanh cho đến khi biên dịch lại mô-đun hoặc SiteManager.clear_cache () phương pháp được gọi là. Xem: code.djangoproject.com/svn/django/tags/release/1.3/django/ Kẻ
Đại tá Sponsz

Câu trả lời:


512

Sử dụng phương thức request.build_absolute_uri () tiện dụng theo yêu cầu, chuyển cho nó url tương đối và nó sẽ cung cấp cho bạn đầy đủ.

Theo mặc định, URL tuyệt đối cho request.get_full_path()được trả về, nhưng bạn có thể chuyển cho nó một URL tương đối làm đối số đầu tiên để chuyển đổi nó thành một URL tuyệt đối.


3
Còn url: localhost / home / # / test thì sao? Tôi chỉ có thể thấy localhost / home . Làm thế nào tôi có thể nhìn thấy phần sau sắc nét ?
sergzach

41
mọi thứ sau khi # không được chuyển đến máy chủ, đó là tính năng chỉ dành cho trình duyệt
Dmitry Shevchenko

70
Trong một mẫu (nơi bạn không thể đưa ra các tham số), bạn chỉ có thể thực hiện việc này: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- và heyho, url đầy đủ.
odinho - Velmont

17
Và nếu tôi không có quyền truy cập để yêu cầu thì sao? Giống như trong Bộ nối tiếp của Django-REST-Framework?
Minder

15
Tôi đã phải sử dụng {% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}{{ request.build_absolute_uri }}có dấu gạch chéo và {{ object.get_absolute_url }}bắt đầu bằng dấu gạch chéo dẫn đến dấu gạch chéo kép trong URL.
xtranophilist

96

Nếu bạn muốn sử dụng nó với reverse()bạn có thể làm điều này:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
Cảm ơn câu trả lời hữu ích. Không có gì tốt hơn chính mã. (ngoài ra, bạn có thể có nghĩa là url_namethay vì view_name)
Anupam

3
@Anupam Reverse () được định nghĩa là:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

Bạn cũng có thể sử dụng get_current_sitenhư một phần của ứng dụng trang web ( from django.contrib.sites.models import get_current_site). Nó nhận một đối tượng yêu cầu và mặc định cho đối tượng trang web mà bạn đã cấu hình SITE_IDtrong settings.txt nếu yêu cầu là None. Đọc thêm trong tài liệu để sử dụng khung trang web

ví dụ

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

Nó không nhỏ gọn / gọn gàng như request.build_absolute_url(), nhưng có thể sử dụng được khi các đối tượng yêu cầu không có sẵn và bạn có một url trang mặc định.


4
Tôi tin rằng câu hỏi của tôi đặc biệt nói "không có mô-đun Trang web". Điều này có đánh vào DB không?
mở

1
Mô-đun Trang web đã được ghi vào bộ đệm đối tượng Trang web bằng cách sử dụng bộ đệm ẩn cấp mô-đun (tức là bạn không cần khung bộ đệm), do đó, DB chỉ nên bị tấn công lần đầu tiên khi Trang web được truy xuất bởi một quy trình web. Nếu bạn không có django.contrib.sitestrong bạn INSTALLED_APPS, nó sẽ không đánh DB ở tất cả, và cung cấp thông tin dựa trên đối tượng Request (xem get_current_site )
Darb

1
Vậy thì bạn có thể có +1, nhưng build_absolute_urivẫn giống như giải pháp dễ dàng và sạch sẽ hơn.
mpen

1
Đây là một câu trả lời hoàn hảo nếu bạn đang cố gắng tạo URL trong các tín hiệu để gửi email từ đó.
Chris

2
Không hoạt động, nếu bạn sử dụng https. Vâng, bạn có thể thêm s, nhưng bạn có phát triển với https cục bộ không? và bạn có luôn biết, nếu bạn có https nhưng đôi khi không ...?
tjati

55

Nếu bạn không thể truy cập requestthì bạn không thể sử dụng get_current_site(request)như được đề xuất trong một số giải pháp tại đây. Bạn có thể sử dụng kết hợp khung Trang web gốc vàget_absolute_url thay vào đó. Thiết lập ít nhất một Trang web trong quản trị viên, đảm bảo mô hình của bạn có phương thức get_absolute_url () , sau đó:

>>> 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-civerse-domain-for-full-urls


7
Điều này thực sự tiện dụng khi bạn không có quyền truy cập vào đối tượng HttpRequest. ví dụ: trong các nhiệm vụ, tín hiệu, v.v.
Arsham

6
trước khi sử dụng, bạn nên kích hoạt khung trang web docs.djangoproject.com/en/dev/ref/contrib/sites/ mẹo
madzohan

Để thay đổi example.com thành một cái gì đó cũng: Site.objects.all () [0] trả về 'example.com' và có id = 1, được chỉ định trong settings.py. Chỉ cần làm Site.objects.create (name = 'sản xuất', domain = 'prodsite.com') và đặt SITE_ID = 2 trong settings.py. Bây giờ Site.objects.get_cản (). Tên miền trả về 'prodsite.com'.
gek

Bạn có thể thiết lập requestđể Nonehoặc gọi get_current_site(None).
Bobort

20

Nếu bạn không muốn truy cập cơ sở dữ liệu, bạn có thể thực hiện với cài đặt. Sau đó, sử dụng bộ xử lý ngữ cảnh để thêm nó vào mọi mẫu:

# 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

Theo quan điểm của bạn, chỉ cần làm điều này:

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

14

django-fullurl

Nếu bạn đang cố gắng thực hiện điều này trong mẫu Django, tôi đã phát hành gói PyPI nhỏ django-fullurlđể cho phép bạn thay thế urlstaticgắn thẻ mẫu bằng fullurlfullstaticnhư thế này:

{% load fullurl %}

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

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

Những huy hiệu này hy vọng sẽ được cập nhật tự động:

PyPI Travis CI

Trong một cái nhìn, tất nhiên bạn có thể sử dụng request.build_absolute_urithay thế.


Thật xấu hổ vì điều này không hoạt động với 2.0. Có thể cần phải đẩy lên một PR.
Nhà thờ Steven

@StevenChurch Nó nên hoạt động. Tôi chưa đánh dấu Django 2.0 là được hỗ trợ, nhưng phiên bản hiện tại sẽ hoạt động.
Flimm

Đối với nhu cầu của tôi, tôi đã vượt qua điều này bằng cách chuyển ENV từ Heroku cho failback. Vấn đề của tôi là nhận được URL để chuyển qua các mẫu email. Tôi không thể nhớ vấn đề nhưng nó không hoạt động do thay đổi Django.
Nhà thờ Steven

@StevenChurch Tôi nghĩ vấn đề khi tạo email là không có requestđối tượng để lấy tên miền từ đó. Trong trường hợp đó, bạn nên sử dụng siteskhung thay thế, lấy tên miền từ cơ sở dữ liệu. Xem django-absoluteuri, được đề cập trong phần "xem thêm" trong phần README của gói PyPI này.
Flimm

8

Để tạo một liên kết hoàn chỉnh đến một trang khác từ một mẫu, bạn có thể sử dụng điều này:

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

request.META.HTTP_HOST cung cấp tên máy chủ và url cung cấp tên tương đối. Công cụ mẫu sau đó ghép chúng thành một url hoàn chỉnh.


2
Câu trả lời là thiếu giao thức ( httptrong ngữ cảnh này) và ://một phần của URL, vì vậy nó sẽ không cung cấp một url hoàn chỉnh .
dùng272735

2
Đối tượng yêu cầu có một máy chủ lưu trữ trên đó. Đừng kiểm tra meta trực tiếp: docs.djangoproject.com/en/1.8/ref/request-response/ mẹo
Kit Sunde

8

Một cách khác. Bạn có thể sử dụng build_absolute_uri()trong của bạn view.pyvà chuyển nó vào mẫu.

xem

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)tương đương với request.build_absolute_uri()nó phải không?
mở


7

Hãy thử đoạn mã sau:

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

Điều đó sẽ chỉ cung cấp cho tên miền mà không có đường dẫn và chuỗi truy vấn, phải không?
mở

6

Điều này làm việc cho tôi trong mẫu của tôi:

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

Tôi cần url đầy đủ để chuyển nó đến một chức năng tìm nạp js. Tôi hy vọng điều này sẽ giúp bạn.


5

Tôi biết đây là một câu hỏi cũ. Nhưng tôi nghĩ mọi người vẫn chạy vào đây rất nhiều.

Có một vài thư viện ngoài đó bổ sung chức năng Django mặc định. Tôi đã thử một vài. Tôi thích thư viện sau đây khi tham chiếu ngược các url tuyệt đối:

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

Một cái khác tôi thích vì bạn có thể dễ dàng kết hợp một tên miền, giao thức và đường dẫn là:

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

Thư viện này cho phép bạn chỉ cần viết những gì bạn muốn trong mẫu của bạn, ví dụ:

{{url_parts.domain}}

4

Nếu bạn đang sử dụng khung django REST, bạn có thể sử dụng chức năng đảo ngược từ rest_framework.reverse. Điều này có hành vi tương tự như django.core.urlresolvers.reverse, ngoại trừ việc nó sử dụng tham số yêu cầu để xây dựng một URL đầy đủ.

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

Đã chỉnh sửa để chỉ đề cập đến tính khả dụng trong khung REST


Tôi nhận được một lỗi sử dụng request=request. Có vẻ như yêu cầu không được ghi lại ở đây docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos

Tôi quên đề cập đến điều này chỉ khả dụng nếu bạn đang sử dụng khung REST. Bắt tốt, tôi đã cập nhật câu trả lời của tôi.
JohnG

Vâng cảm ơn bạn - điều này hoạt động như một cơ duyên với khung django REST
Apoorv Kansal

1

Tôi hiểu rồi:

wsgiref.util.request_uri(request.META)

Nhận đầy đủ uri với lược đồ, máy chủ, đường dẫn cổng và truy vấn.


0

Ngoài ra còn có ABSOLUTE_URL_OVERRIDES dưới dạng cài đặt

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

Nhưng điều đó ghi đè get_absolute_url (), có thể không được mong muốn.

Thay vì cài đặt khung trang web chỉ cho việc này hoặc thực hiện một số nội dung khác được đề cập ở đây dựa trên đối tượng yêu cầu, tôi nghĩ giải pháp tốt hơn là đặt điều này trong mô hình.

Xác định BASE_URL trong settings.txt, sau đó nhập nó vào model.py và tạo một lớp trừu tượng (hoặc thêm nó vào một lớp bạn đang sử dụng) xác định get_truly_absolute_url (). Nó có thể đơn giản như:

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

Phân lớp nó và bây giờ bạn có thể sử dụng nó ở khắp mọi nơi.


0

Như đã đề cập trong các câu trả lời khác, request.build_absolute_uri()là hoàn hảo nếu bạn có quyền truy cập requestsites khung là tuyệt vời miễn là các URL khác nhau trỏ đến các cơ sở dữ liệu khác nhau.

Tuy nhiên, trường hợp sử dụng của tôi là hơi khác nhau. Máy chủ dàn của tôi và máy chủ sản xuất truy cập cùng một cơ sở dữ liệu, nhưng get_current_sitecả hai đều trả về cái đầu tiên sitetrong cơ sở dữ liệu. Để giải quyết điều này, bạn phải sử dụng một số loại biến môi trường. Bạn có thể sử dụng 1) biến môi trường (đại loại như os.environ.get('SITE_URL', 'localhost:8000')) hoặc 2) khác nhau SITE_IDcho các máy chủ khác nhaucài đặt khác nhau .

Hy vọng ai đó sẽ tìm thấy điều này hữu ích!


0

Tôi đã xem qua chủ đề này bởi vì tôi đang tìm cách xây dựng một URI tuyệt đối cho một trang thành công. request.build_absolute_uri()đã cho tôi một URI cho chế độ xem hiện tại của tôi nhưng để có được URI cho chế độ xem thành công của tôi, tôi đã sử dụng như sau ....

request.build_absolute_uri (đảo ngược ('thành công_view_name'))


-2

request.get_host() sẽ cung cấp cho bạn tên miền.


1
Câu hỏi nêu rõ, URL đầy đủ
acidjunk

-5

Bạn cũng có thể dùng:

import socket
socket.gethostname()

Điều này đang làm việc tốt cho tôi,

Tôi không hoàn toàn chắc chắn làm thế nào nó hoạt động. Tôi tin rằng đây là cấp độ thấp hơn một chút và sẽ trả về tên máy chủ của bạn, có thể khác với tên máy chủ được người dùng của bạn sử dụng để truy cập trang của bạn.


Vâng..bạn đã chỉ ra vấn đề. Tên máy chủ không nhất thiết phải giống như tên miền.
mở

Điều này giải quyết một vấn đề rất khác nhau. Hãy xem xét một máy chủ lưu trữ được chia sẻ với nhiều trang web - sử dụng mã ở trên, tất cả các trang web tạo URL sẽ có tất cả các URL như vậy trỏ đến máy chủ, có khả năng KHÔNG phải bất kỳ trang web nào đang chạy.
tbm

-6

Bạn có thể thử "request.get_full_path ()"


3
Điều này không bao gồm tên miền.
TAH
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.