สิ่งที่ตรงกันข้าม () ใน Django


219

เมื่อฉันอ่านรหัส Django reverse()บางครั้งที่ฉันเห็นในบางแม่ ฉันไม่แน่ใจว่าสิ่งนี้คืออะไร แต่มันถูกใช้ร่วมกับ HttpResponseRedirect reverse()ควรใช้สิ่งนี้อย่างไรและเมื่อไหร่?

มันจะดีถ้ามีคนให้คำตอบด้วยตัวอย่างบางส่วน ...


26
กำหนดรูปแบบ URL Django ใช้ url () เพื่อเลือกมุมมองที่ถูกต้องและสร้างหน้า นั่นคือurl--> view name. แต่บางครั้งเช่นเมื่อเปลี่ยนเส้นทางคุณต้องไปในทิศทางตรงกันข้ามและตั้งชื่อมุมมองให้ Django และ Django สร้าง URL ที่เหมาะสม กล่าวอีกนัยหนึ่ง, view name --> url. นั่นคือreverse()(มันคือการย้อนกลับของฟังก์ชัน url) มันอาจดูโปร่งใสกว่าที่จะโทรgenerateUrlFromViewNameแต่มันยาวเกินไปและอาจไม่กว้างพอ: docs.djangoproject.com/en/dev/topics/http/urls/ …
eric

4
@neononet คำอธิบายที่ดีขอบคุณ ชื่อนี้ดูเหมือน (และดูเหมือน) โดยเฉพาะอย่างยิ่งฉันไม่ได้ใช้งานง่ายซึ่งฉันถือเป็นบาปร้ายแรง ใครไม่เกลียดความงงงวยที่ไม่จำเป็น?
ไมค์หนู

นี่คือตัวอย่างทั่วไปของการตั้งชื่อที่เน้นด้านหนึ่งของเอนทิตี (เช่นฟังก์ชัน) ที่สำคัญที่สุดในใจของโปรแกรมเมอร์ในเวลาที่กำหนดบริบทของเขา แต่ไม่ใช่ตัวเลือกที่มีประโยชน์มากที่สุดในบริบทกว้างของนักพัฒนาอื่น ๆ . เรามักจะตกหลุมพรางนี้เนื่องจากโปรแกรมเมอร์ - การตั้งชื่อมีความสำคัญต่อการค้นพบมันคุ้มค่าที่จะหยุดและคิดเกี่ยวกับบริบทที่แตกต่างกันและเลือกสิ่งที่เหมาะสมที่สุด
Cornel Masson

คำตอบ:


347

reverse()| เอกสาร Django


สมมติว่าurls.pyคุณได้กำหนดสิ่งนี้ไว้ใน:

url(r'^foo$', some_view, name='url_name'),

ในเทมเพลตคุณสามารถอ้างถึง url นี้เป็น:

<!-- django <= 1.4 -->
<a href="{% url url_name %}">link which calls some_view</a>

<!-- django >= 1.5 or with {% load url from future %} in your template -->
<a href="{% url 'url_name' %}">link which calls some_view</a>

สิ่งนี้จะแสดงผลเป็น:

<a href="/foo/">link which calls some_view</a>

ตอนนี้ว่าคุณต้องการที่จะทำบางสิ่งบางอย่างที่คล้ายกันในของคุณviews.py- เช่นคุณมีการจัดการ URL อื่น ๆ บาง (ไม่/foo/) ในบางมุมมองอื่น ๆ (ไม่ได้some_view) และคุณต้องการที่จะเปลี่ยนเส้นทางให้ผู้ใช้/foo/(มักจะเป็นกรณีการส่งแบบฟอร์มการประสบความสำเร็จ)

คุณสามารถทำได้:

return HttpResponseRedirect('/foo/')

แต่ถ้าคุณต้องการเปลี่ยน URL ในอนาคตล่ะ คุณต้องอัปเดตurls.py และการอ้างอิงทั้งหมดในรหัสของคุณ สิ่งนี้ละเมิดDRY (อย่าทำซ้ำตัวเอง)ความคิดทั้งหมดในการแก้ไขเพียงแห่งเดียวเท่านั้นซึ่งเป็นสิ่งที่เราต้องพยายาม

คุณสามารถพูดได้ว่า:

from django.urls import reverse
return HttpResponseRedirect(reverse('url_name'))

ลักษณะนี้ผ่าน URL ทั้งหมดที่กำหนดไว้ในโครงการของคุณสำหรับ URL ที่กำหนดไว้มีชื่อurl_nameและส่งกลับ /foo/URL

ซึ่งหมายความว่าคุณหมายถึง URL โดยเฉพาะของnameแอตทริบิวต์ - ถ้าคุณต้องการที่จะเปลี่ยน URL ตัวเองหรือมุมมองมันหมายถึงคุณสามารถทำได้โดยการแก้ไขที่เดียวเท่านั้น urls.py-


3
FYI {{ url 'url_name' }}ควรอยู่{% url url_name %}ใน Django 1.4 หรือเก่ากว่า นี้จะมีการเปลี่ยนแปลงในรุ่น Django ถัดไป (1.5) {% url 'url_name' %}และจากนั้นควรจะเป็น เอกสารสำหรับtemplatetag ของ urlให้ข้อมูลที่ดีถ้าคุณเลื่อนลงไปที่ส่วน "การทำงานร่วมกันได้ต่อไป"
j_syk

1
j_syk ขอบคุณ - ฉันทำ @load url จากอนาคต @ ตั้งแต่ 1.3 ออกมาและลืมไปแล้วว่ามันยังไม่ใช่ค่าเริ่มต้น ฉันจะอัปเดตคำตอบของฉันเพื่อไม่ให้พลาดประสบการณ์
scytale

2
ถาวร - ฉันคิดว่ามันถือว่าเป็นที่ยอมรับกันโดยสิ้นเชิงสำหรับคุณที่จะแก้ไขความผิดพลาดโง่ในคำตอบของคนอื่น ๆ ด้วยตัวเองดังนั้นหากคุณเห็นมากขึ้นเพียงแค่กระโดดใน :-)
Scytale

3
หนึ่งในคำตอบที่ละเอียดอ่อนที่สุดที่พบได้ในเว็บไซต์นี้
มนัส Chaturvedi

1
">>> แต่จะเป็นอย่างไรถ้าคุณต้องการเปลี่ยน URL ในอนาคต", รายละเอียดปลีกย่อยเหล่านี้จะมีประโยชน์ในเวลา. 1,0001% ของเวลาและการแก้ปัญหานั้นถูกส่งมาเหมือนฟีเจอร์ที่มีประโยชน์และผู้คนใช้มันราวกับว่าพวกเขาเป็น แนวปฏิบัติที่ดีที่สุดและทิ้งความยุ่งเหยิง TBH ถ้าเมื่อมีการเปลี่ยนแปลง URL ในอนาคตคุณเพียงแค่ทำการค้นหาทั่วโลกแทน แม้แต่โซลูชันนี้ (ใช้ url_name) ก็มีแนวโน้มที่จะเกิดปัญหาของ 'จะเกิดอะไรขึ้นถ้าคุณต้องการเปลี่ยน url_name ในอนาคต' รับเขียนโปรแกรมใน Django มานานกว่า 5 url_reverseปีและยังไม่ได้ตอบสนองความต้องการสำหรับ วิธีที่ดีที่สุดในการจัดการกับสิ่งแปลกประหลาดประเภทนี้คือการปฏิเสธที่จะใช้มัน
nehem

10

นี่เป็นคำถามเก่า แต่นี่คือสิ่งที่อาจช่วยใครบางคน

จากเอกสารอย่างเป็นทางการ:

Django มีเครื่องมือสำหรับการย้อนกลับ URL ที่ตรงกับเลเยอร์ต่างๆที่จำเป็นต้องใช้ URL: ในเทมเพลต: การใช้แท็กเทมเพลต url ในรหัสไพ ธ อน: การใช้ฟังก์ชัน reverse () ในรหัสระดับที่สูงขึ้นเกี่ยวข้องกับการจัดการ URL ของอินสแตนซ์โมเดล Django: เมธอด get_absolute_url ()

เช่น. ในเทมเพลต (แท็ก url)

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

เช่น. ในรหัสหลาม (ใช้reverseฟังก์ชั่น)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

1
ต้องการบอสรายละเอียดแบบเต็ม
Job

OP กล่าวโดยเฉพาะว่าเขาอ่านเอกสารเขาต้องการคำอธิบายไม่ใช่เพียงแค่คัดลอก / วางจากเอกสาร
RusI

8

คำตอบที่มีอยู่ทำได้ดีมากในการอธิบายว่าreverse()ฟังก์ชัน นี้ใน Django เป็นอย่างไร

แต่ผมหวังว่าคำตอบของฉันหลั่งน้ำตาแสงที่แตกต่างกันที่ว่าทำไมทำไมการใช้งานreverse()ในสถานที่ตรงไปตรงมามากขึ้นวิธีการเนื้อหา pythonic อื่น ๆ ในแม่แบบของมุมมองที่มีผลผูกพันและสิ่งที่เป็นบางเหตุผลที่ถูกต้องสำหรับความนิยมของคนนี้ "เปลี่ยนเส้นทางผ่าน reverse()รูปแบบ "ในตรรกะการกำหนดเส้นทาง Django

ประโยชน์ที่สำคัญอย่างหนึ่งคือการสร้าง URL ย้อนกลับตามที่คนอื่น ๆ ได้กล่าวถึง เช่นเดียวกับวิธีการที่คุณจะใช้{% url "profile" profile.id %}ในการสร้าง URL จากแฟ้มการกำหนดค่า URL path('<int:profile.id>/profile', views.profile, name="profile")ของแอปนี้เช่น

แต่เป็น OP ได้ตั้งข้อสังเกตการใช้ยังจะถูกรวมโดยทั่วไปกับการใช้งานของreverse() HttpResponseRedirectแต่ทำไม

ฉันไม่แน่ใจว่าสิ่งนี้คืออะไร แต่มันถูกใช้ร่วมกับ HttpResponseRedirect ควรใช้ reverse นี้อย่างไรและเมื่อใด?

พิจารณาสิ่งต่อไปนี้views.py:

from django.http import HttpResponseRedirect
from django.urls import reverse

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected = question.choice_set.get(pk=request.POST['choice'])
    except KeyError:
        # handle exception
        pass
    else:
        selected.votes += 1
        selected.save()
        return HttpResponseRedirect(reverse('polls:polls-results',
                                    args=(question.id)
        ))

และความเรียบง่ายของเราurls.py:

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('<int:question_id>/results/', views.results, name='polls-results'),
    path('<int:question_id>/vote/', views.vote, name='polls-vote')
]

ในvote()ฟังก์ชั่นรหัสในelseบล็อกของเราใช้reverseพร้อมกับHttpResponseRedirectในรูปแบบต่อไปนี้:

HttpResponseRedirect(reverse('polls:polls-results',
                                        args=(question.id)

สิ่งแรกและสำคัญที่สุดนี้หมายความว่าเราไม่จำเป็นต้องเข้ารหัสฮาร์ดโค้ด (สอดคล้องกับหลักการ DRY) แต่สำคัญยิ่งกว่านั้นreverse()เป็นวิธีที่สวยงามในการสร้างสตริง URL โดยการจัดการค่าที่args=(question.id)คลายจากอาร์กิวเมนต์ ( จัดการโดย URLConfig) ควรquestionมีคุณสมบัติidที่มีค่า5URL ที่สร้างจากreverse()นั้นจะเป็น:

'/polls/5/results/'

ในรหัสการเชื่อมโยงมุมมองเทมเพลตปกติเราใช้HttpResponse()หรือrender()ตามปกติแล้วจะเกี่ยวข้องกับสิ่งที่เป็นนามธรรมน้อยกว่า: ฟังก์ชันหนึ่งมุมมองที่ส่งคืนหนึ่งเทมเพลต:

def index(request):
    return render(request, 'polls/index.html') 

แต่ในหลายกรณีการเปลี่ยนเส้นทางที่ถูกกฎหมายเรามักสนใจสร้าง URL จากรายการพารามิเตอร์ รวมถึงกรณีต่าง ๆ เช่น:

  • ส่งแบบฟอร์ม HTML ผ่านPOSTคำขอ
  • โพสต์การตรวจสอบการเข้าสู่ระบบของผู้ใช้
  • รีเซ็ตรหัสผ่านผ่านโทเค็นเว็บ JSON

สิ่งเหล่านี้ส่วนใหญ่เกี่ยวข้องกับการเปลี่ยนเส้นทางรูปแบบบางส่วนและ URL ที่สร้างผ่านชุดพารามิเตอร์ หวังว่านี่จะช่วยเพิ่มคำตอบที่เป็นประโยชน์แล้ว!


4

ฟังก์ชั่นรองรับหลักการแบบแห้ง - ให้แน่ใจว่าคุณไม่ได้ใส่รหัสยากในแอพของคุณ ควรกำหนด url ในที่เดียวและที่เดียวเท่านั้น - url ของคุณจะเป็นที่ยอมรับ หลังจากนั้นคุณเพียงแค่อ้างอิงข้อมูลนั้น

ใช้reverse()เพื่อให้ URL ของหน้าเว็บที่กำหนดให้กับเส้นทางไปยังมุมมองหรือพารามิเตอร์ page_name จาก url conf ของคุณ {% url 'my-page' %}คุณจะใช้มันในกรณีที่มันไม่ได้ทำให้ความรู้สึกที่จะทำมันในแม่แบบที่มี

มีสถานที่ที่เป็นไปได้มากมายที่คุณอาจใช้ฟังก์ชันนี้ ที่เดียวที่ฉันพบฉันใช้คือเมื่อเปลี่ยนเส้นทางผู้ใช้ในมุมมอง (บ่อยครั้งหลังจากการประมวลผลแบบฟอร์มสำเร็จ) -

return HttpResponseRedirect(reverse('thanks-we-got-your-form-page'))

คุณอาจใช้เมื่อเขียนแท็กเทมเพลต

อีกครั้งที่ฉันใช้reverse()อยู่กับมรดกรุ่น ฉันมี ListView ในรูปแบบผู้ปกครอง แต่ต้องการได้รับจากวัตถุแม่ใด ๆ เหล่านั้นไปยัง DetailView ของวัตถุลูกที่เกี่ยวข้อง ผมแนบget__child_url()ฟังก์ชั่นไปยังผู้ปกครองที่ระบุการดำรงอยู่ของเด็กและกลับ URL ของมัน DetailView reverse()โดยใช้


4

มีเอกสารสำหรับสิ่งนั้น

https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-resolution-of-urls

มันสามารถใช้ในการสร้าง URL สำหรับมุมมองที่กำหนด

ข้อได้เปรียบหลักคือคุณไม่ได้กำหนดเส้นทางรหัสยากในรหัส


2

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


1
เพียงแค่เรียนรู้ Django จากการสอน (Django Girls) มันเป็นช่วงการเรียนรู้ที่สูงชัน ฉันคิดว่าชื่อฟังก์ชั่นนี้น่ากลัว: "สำรอง" โดยไม่มีคุณสมบัติใด ๆ เลยแนะนำอย่างยิ่งให้จองรายการหรือสตริงซึ่งเห็นได้ชัดว่าไม่มีอะไรเกี่ยวข้องกับมัน
mike rodent

@ Mikerodent ฉันเห็นด้วยกับคุณอย่างสมบูรณ์ นอกจากนี้ยังไม่มีคำตอบใด ๆ ที่อธิบายว่าทำไมฟังก์ชันจึงถูกเรียก มันช่างเป็นชื่อที่ไม่ดี
Soham Dongargaonkar

1

reverse () ใช้เพื่อยึดหลักการ django DRY เช่นหากคุณเปลี่ยน url ในอนาคตคุณสามารถอ้างอิง url นั้นโดยใช้ reverse (urlname)

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