ฉันจะรับ URL แบบเต็ม / สัมบูรณ์ (ด้วยโดเมน) ใน Django ได้อย่างไร


379

ฉันจะรับ URL แบบเต็ม / สัมบูรณ์ (เช่นhttps://example.com/some/path) ใน Django โดยไม่มีโมดูล Sites ได้อย่างไร นั่นมันช่างงี่เง่า ... ฉันไม่จำเป็นต้องค้นหา DB เพื่อขัดขวาง URL!

reverse()ฉันต้องการที่จะใช้กับ


11
เช่นกัน: โมดูลไซต์จะเข้าถึงฐานข้อมูลได้เพียงครั้งแรกที่ต้องการชื่อไซต์ผลลัพธ์จะถูกแคชในตัวแปรโมดูล (SITE_CACHE) ที่จะวนไปเรื่อย ๆ จนกว่าจะรวบรวมโมดูลหรือ SiteManager.clear_cache () อีกครั้ง วิธีการที่เรียกว่า ดู: code.djangoproject.com/svn/django/tags/releases/1.3/django/…
พันเอกส

คำตอบ:


512

ใช้คำขอที่มีประโยชน์build_absolute_uri ()วิธีการตามคำขอผ่าน URL สัมพัทธ์และจะให้เต็ม

ตามค่าเริ่มต้น URL แบบสัมบูรณ์สำหรับrequest.get_full_path()จะถูกส่งคืน แต่คุณสามารถส่ง URL แบบสัมพัทธ์เป็นอาร์กิวเมนต์แรกเพื่อแปลงเป็น URL แบบสัมบูรณ์


3
แล้ว url: localhost / home / # / testล่ะ? ฉันเห็นlocalhost / homeเท่านั้น ฉันจะดูส่วนหลังจากคมได้อย่างไร
sergzach

41
ทุกอย่างหลังจากที่ # ไม่ได้ผ่านไปยังเซิร์ฟเวอร์มันเป็นคุณสมบัติของเบราว์เซอร์เท่านั้น
Dmitry Shevchenko

69
ในเทมเพลต (ซึ่งคุณไม่สามารถให้พารามิเตอร์) คุณสามารถทำสิ่งนี้: {{ request.build_absolute_uri }}{{ object.get_absolute_url }}- และ heyho, url เต็ม
odinho - Velmont

17
และถ้าฉันไม่มีสิทธิ์เข้าถึงคำขอล่ะ ชอบใน Serializers ของ Django-REST-Framework เหรอ?
minder

15
ฉันต้องใช้{% if request.is_secure %}https://{% else %}http://{% endif %}{{ request.get_host }}{{ object.get_absolute_url }}เพราะ{{ request.build_absolute_uri }}มีเครื่องหมายทับท้ายและ{{ object.get_absolute_url }}เริ่มต้นด้วยเครื่องหมายทับทำให้มีเครื่องหมายทับสองครั้งใน URL
xtranophilist

96

หากคุณต้องการใช้กับreverse()คุณสามารถทำได้:request.build_absolute_uri(reverse('view_name', args=(obj.pk, )))


3
ขอบคุณสำหรับคำตอบที่เป็นประโยชน์ ไม่มีอะไรดีไปกว่าโค้ดเอง (เช่นคุณอาจหมายถึงurl_nameแทนview_name)
Anupam

3
@Anupam reverse () ถูกกำหนดเป็น:def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
matias elgart

57

คุณสามารถใช้get_current_siteเป็นส่วนหนึ่งของแอปไซต์ ( from django.contrib.sites.models import get_current_site) มันต้องใช้วัตถุคำขอและค่าเริ่มต้นไปยังเว็บไซต์ของวัตถุที่คุณได้กำหนดค่าด้วยSITE_IDใน settings.py Noneถ้าขอเป็น อ่านเพิ่มเติมในเอกสารประกอบการใช้งานเฟรมเวิร์กไซต์

เช่น

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

มันไม่กะทัดรัด / เรียบร้อยเหมือนrequest.build_absolute_url()แต่มันสามารถใช้งานได้เมื่อวัตถุคำขอไม่พร้อมใช้งานและคุณมี URL ไซต์เริ่มต้น


4
ฉันเชื่อว่าคำถามของฉันพูดโดยเฉพาะ "ไม่มีโมดูล Sites" สิ่งนี้กระทบฐานข้อมูลหรือไม่
mpen

1
โมดูล Sites ได้รับการเขียนไปยังแคชวัตถุของไซต์โดยใช้การแคชระดับโมดูล (เช่นคุณไม่จำเป็นต้องใช้เฟรมเวิร์กแคช) ดังนั้น DB ควรได้รับการเข้าชมในครั้งแรกที่มีการเรียกเว็บไซต์โดยกระบวนการเว็บ หากคุณไม่ได้มีdjango.contrib.sitesในของคุณINSTALLED_APPSก็จะไม่ตีฐานข้อมูลที่ทุกคนและให้ข้อมูลที่อยู่บนพื้นฐานของการร้องขอวัตถุ (ดูget_current_site )
Darb

1
ถ้าอย่างนั้นคุณสามารถมี +1 ได้ แต่build_absolute_uriก็ยังดูเหมือนโซลูชันที่ง่ายกว่าและสะอาดกว่า
mpen

1
นี่เป็นคำตอบที่สมบูรณ์แบบหากคุณพยายามสร้าง URL ในสัญญาณเพื่อส่งอีเมลจาก
Chris

2
ไม่ทำงานหากคุณใช้ https ใช่คุณสามารถเพิ่ม s แต่คุณพัฒนาด้วย https ภายในเครื่องหรือไม่ และคุณรู้อยู่เสมอว่าคุณมี https แต่บางครั้งก็ไม่ ...
tjati

55

หากคุณไม่สามารถเข้าถึงได้requestคุณจะไม่สามารถใช้งานได้get_current_site(request)ตามที่แนะนำในโซลูชันบางอย่างที่นี่ คุณสามารถใช้การรวมกันของเฟรมเวิร์กไซต์ดั้งเดิมและget_absolute_urlแทน ตั้งค่าอย่างน้อยหนึ่งไซต์ในผู้ดูแลระบบตรวจสอบให้แน่ใจว่าแบบจำลองของคุณมีเมธอด get_absolute_url ()จากนั้น:

>>> 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
สิ่งนี้มีประโยชน์จริง ๆ เมื่อคุณไม่สามารถเข้าถึงวัตถุ HttpRequest เช่นในงานสัญญาณ ฯลฯ
Arsham

6
ก่อนที่จะใช้สิ่งนี้คุณควรเปิดใช้งานเฟรมเวิร์กไซต์docs.djangoproject.com/en/dev/ref/contrib/sites/…
madzohan

หากต้องการเปลี่ยน example.com เป็นบางอย่างด้วย: Site.objects.all () [0] ส่งคืน 'example.com' และมี id = 1 ซึ่งระบุไว้ใน settings.py เพียงทำ Site.objects.create (name = 'production', domain = 'prodsite.com') และตั้ง SITE_ID = 2 ใน settings.py ตอนนี้ Site.objects.get_current (). โดเมนจะส่งคืน 'prodsite.com'
gek

คุณสามารถตั้งค่าrequestการหรือโทรNone get_current_site(None)
Bobort

20

หากคุณไม่ต้องการที่จะตีฐานข้อมูลคุณสามารถทำได้ด้วยการตั้งค่า จากนั้นใช้ตัวประมวลผลบริบทเพื่อเพิ่มลงในทุกเทมเพลต:

# 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>


14

django-fullurl

หากคุณกำลังพยายามทำสิ่งนี้ในเทมเพลต Django ฉันได้เปิดตัวแพ็คเกจ PyPI ขนาดเล็กdjango-fullurlเพื่อให้คุณแทนที่urlและstaticเทมเพลตแท็กด้วยfullurlและfullstaticเช่นนี้:

{% load fullurl %}

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

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

ป้ายเหล่านี้หวังว่าจะได้รับการอัปเดตโดยอัตโนมัติ:

PyPI เทรวิส CI

ในมุมมองคุณสามารถใช้request.build_absolute_uriแทนแน่นอน


ความอัปยศนี้ใช้ไม่ได้กับ 2.0 อาจจำเป็นต้องผลักดันการประชาสัมพันธ์
โบสถ์สตีเวน

@ StevenChurch มันควรจะทำงาน ฉันยังไม่ได้ทำเครื่องหมาย Django 2.0 ว่ารองรับ แต่รุ่นที่มีอยู่ควรใช้งานได้
Flimm

สำหรับความต้องการของฉันฉันได้รับสิ่งนี้โดยส่ง ENV จาก Heroku เพื่อให้เกิดความล้มเหลว ปัญหาของฉันคือการรับ URL เพื่อส่งผ่านไปยังแม่แบบอีเมล ฉันจำปัญหาไม่ได้ แต่มันไม่ทำงานเนื่องจากการเปลี่ยนแปลง Django
Steven Church

@StevenChurch ฉันคิดว่าปัญหาเมื่อสร้างอีเมลคือไม่มีrequestวัตถุที่จะได้รับชื่อโดเมน ในกรณีนี้คุณควรใช้sitesเฟรมเวิร์กแทนซึ่งรับชื่อโดเมนจากฐานข้อมูล โปรดดูที่django-absoluteuriกล่าวถึงในส่วน "ดูเพิ่มเติม" ของ README ของแพ็คเกจ PyPI นี้
Flimm

8

หากต้องการสร้างลิงก์ที่สมบูรณ์ไปยังหน้าอื่นจากเทมเพลตคุณสามารถใช้สิ่งนี้:

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

request.META.HTTP_HOST ให้ชื่อโฮสต์และ url ให้ชื่อที่เกี่ยวข้อง เทมเพลตเอ็นจิ้นนั้นจะรวมเข้าเป็น url ที่สมบูรณ์


2
คำตอบจะหายไปโปรโตคอล ( httpในบริบทนี้) และ://ส่วนหนึ่งของ URL จึงจะไม่ให้URL ที่สมบูรณ์
user272735

2
วัตถุคำขอมีโฮสต์อยู่ อย่าตรวจสอบเมตาโดยตรง: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde

8

อีกวิธีหนึ่ง คุณสามารถใช้build_absolute_uri()ในของคุณview.pyและส่งไปยังแม่แบบ

view.py

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

ของคุณ template.html

{{ baseurl }}

HttpRequest.build_absolute_uri(request)เทียบเท่ากับrequest.build_absolute_uri()มันใช่มั้ย
mpen

7

ตรวจสอบRequest.METAพจนานุกรมที่เข้ามาฉันคิดว่ามันมีชื่อเซิร์ฟเวอร์และเซิร์ฟเวอร์พอร์ต


2
ใช้ request.META ['HTTP_HOST']
แอนโทนี

4
วัตถุคำขอมีโฮสต์อยู่ อย่าตรวจสอบเมตาโดยตรง: docs.djangoproject.com/en/1.8/ref/request-response/…
Kit Sunde


6

สิ่งนี้ใช้ได้กับฉันในเทมเพลตของฉัน:

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

ฉันต้องการ URL แบบเต็มเพื่อส่งต่อไปยังฟังก์ชันดึงข้อมูล js ฉันหวังว่านี่จะช่วยคุณได้


5

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ฉันคิดว่าผู้คนยังคงวิ่งเข้าไปหาสิ่งนี้มากมาย

มีไลบรารีอยู่สองสามตัวที่เสริมการทำงานของ Django ที่เป็นค่าเริ่มต้น ฉันได้ลองมาสองสามครั้งแล้ว ฉันชอบห้องสมุดต่อไปนี้เมื่อย้อนกลับการอ้างอิง URL แบบสัมบูรณ์:

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

อีกอันที่ฉันชอบเพราะคุณสามารถรวบรวมโดเมนโปรโตคอลและพา ธ ได้อย่างง่ายดายคือ:

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

ไลบรารีนี้ให้คุณเขียนสิ่งที่คุณต้องการในเทมเพลตของคุณเช่น:

{{url_parts.domain}}

4

หากคุณกำลังใช้กรอบงาน django REST คุณสามารถใช้ฟังก์ชันย้อนกลับrest_framework.reverseได้ สิ่งนี้มีพฤติกรรมเช่นเดียวกับdjango.core.urlresolvers.reverseยกเว้นว่าจะใช้พารามิเตอร์คำขอเพื่อสร้าง URL แบบเต็ม

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

แก้ไขเพื่อกล่าวถึงความพร้อมใช้งานเฉพาะในกรอบงาน REST


request=requestฉันได้รับข้อผิดพลาดในการใช้ ดูเหมือนว่าคำขอจะไม่ได้รับการบันทึกไว้ที่นี่docs.djangoproject.com/en/1.9/ref/urlresolvers/#reverse
Ryan Amos

ฉันลืมที่จะพูดถึงเรื่องนี้จะใช้ได้เฉพาะในกรณีที่คุณใช้กรอบงาน REST เยี่ยมมากฉันได้อัปเดตคำตอบแล้ว
JohnG

ใช่ขอบคุณ - มันใช้งานได้เป็นอย่างดีกับdjango REST framework
Apoorv Kansal

1

ฉันเข้าใจแล้ว:

wsgiref.util.request_uri(request.META)

รับ uri แบบเต็มด้วย schema โฮสต์เส้นทางของพอร์ตและแบบสอบถาม


0

นอกจากนี้ยังมี ABSOLUTE_URL_OVERRIDES พร้อมตั้งค่า

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

แต่นั่นจะแทนที่ get_absolute_url () ซึ่งอาจไม่เป็นที่ต้องการ

แทนที่จะติดตั้งเฟรมเวิร์กไซต์สำหรับสิ่งนี้หรือทำสิ่งอื่น ๆ ที่กล่าวถึงที่นี่ซึ่งขึ้นอยู่กับวัตถุคำขอฉันคิดว่าทางออกที่ดีกว่าคือการวางสิ่งนี้ไว้ใน models.py

กำหนด BASE_URL ใน settings.py จากนั้นนำเข้าสู่ models.py และสร้างคลาสนามธรรม (หรือเพิ่มเข้าไปในคลาสที่คุณใช้อยู่แล้ว) ซึ่งกำหนด get_truly_absolute_url () มันอาจจะง่ายเหมือน:

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

ซับคลาสมันและตอนนี้คุณสามารถใช้ได้ทุกที่


0

ตามที่กล่าวไว้ในคำตอบอื่น ๆrequest.build_absolute_uri()นั้นสมบูรณ์แบบถ้าคุณสามารถเข้าถึงrequestและsitesกรอบงานนั้นยอดเยี่ยมตราบใดที่ URL ต่าง ๆ ชี้ไปยังฐานข้อมูลที่แตกต่างกัน

อย่างไรก็ตามกรณีการใช้งานของฉันแตกต่างกันเล็กน้อย เซิร์ฟเวอร์ staging ของฉันและเซิร์ฟเวอร์ที่ใช้งานจริงเข้าถึงฐานข้อมูลเดียวกัน แต่get_current_siteทั้งคู่คืนค่าแรกsiteในฐานข้อมูล ในการแก้ไขปัญหานี้คุณต้องใช้ตัวแปรสภาพแวดล้อมบางประเภท คุณสามารถใช้ 1) ตัวแปรสภาพแวดล้อม (สิ่งที่ต้องการos.environ.get('SITE_URL', 'localhost:8000')) หรือ 2) ที่แตกต่างกันSITE_IDสำหรับเซิร์ฟเวอร์ที่แตกต่างกันและsettings.py ที่แตกต่างกัน

หวังว่าบางคนจะพบว่ามีประโยชน์นี้!


0

ฉันเจอชุดข้อความนี้เนื่องจากฉันต้องการสร้าง URI แบบสัมบูรณ์สำหรับหน้าความสำเร็จ request.build_absolute_uri()ให้ URI แก่ฉันสำหรับมุมมองปัจจุบันของฉัน แต่เพื่อให้ได้ URI สำหรับมุมมองความสำเร็จของฉันฉันใช้สิ่งต่อไปนี้ ....

request.build_absolute_uri (ย้อนกลับ ( 'success_view_name'))



-5

คุณยังสามารถใช้:

import socket
socket.gethostname()

มันใช้ได้ดีสำหรับฉัน

ฉันไม่แน่ใจทั้งหมดว่ามันทำงานอย่างไร ฉันเชื่อว่านี่เป็นระดับที่ต่ำกว่าเล็กน้อยและจะส่งคืนชื่อโฮสต์เซิร์ฟเวอร์ของคุณซึ่งอาจแตกต่างจากชื่อโฮสต์ที่ผู้ใช้ของคุณใช้เพื่อไปที่หน้าของคุณ


ใช่ .. คุณชี้ให้เห็นปัญหา ชื่อโฮสต์ไม่จำเป็นต้องเหมือนกับชื่อโดเมน
mpen

วิธีนี้จะช่วยแก้ปัญหาที่แตกต่างกันมาก พิจารณาเซิร์ฟเวอร์โฮสต์ที่ใช้ร่วมกันที่มีหลายเว็บไซต์โดยใช้รหัสด้านบนเว็บไซต์ทั้งหมดที่สร้าง URL จะมี URL ดังกล่าวทั้งหมดชี้ไปที่เครื่องโฮสต์ซึ่งน่าจะไม่ใช่เว็บไซต์ที่ทำงานอยู่
tbm

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.