đảo ngược () trong Django là gì


218

Khi tôi đọc mã django đôi khi, tôi thấy trong một số mẫu reverse(). Tôi không chắc chắn đây là cái gì nhưng nó được sử dụng cùng với HttpResponseRedirect. Làm thế nào và khi nào nó reverse()được sử dụng?

Thật tuyệt nếu ai đó đưa ra câu trả lời với một số ví dụ ...


26
Đưa ra một mẫu url, Django sử dụng url () để chọn chế độ xem đúng và tạo trang. Đó là, url--> view name. Nhưng đôi khi, giống như khi chuyển hướng, bạn cần đi theo hướng ngược lại và đặt cho Django tên của chế độ xem và Django tạo url phù hợp. Nói cách khác , view name --> url. Đó là, reverse()(đó là đảo ngược của chức năng url). Nó có vẻ minh bạch hơn khi chỉ gọi nó generateUrlFromViewNamenhưng quá dài và có thể không đủ chung chung: docs.djangoproject.com/en/dev/topics/http/urls/ Lỗi
eric

4
@neuronet Giải thích tuyệt vời, cảm ơn. Cái tên này dường như (và dường như) đặc biệt không trực quan đối với tôi, mà tôi cho là một tội lỗi nghiêm trọng. Ai không ghét sự xáo trộn không cần thiết?
mike gặm nhấm

Đây là một ví dụ điển hình về việc đặt tên nhấn mạnh một khía cạnh của một thực thể (ví dụ chức năng) mà trước hết là trong tâm trí của lập trình viên, với bối cảnh của anh ta, nhưng không phải là lựa chọn hữu ích nhất trong bối cảnh rộng rãi của bất kỳ nhà phát triển nào khác . Chúng ta thường rơi vào cái bẫy này vì các lập trình viên - việc đặt tên rất quan trọng đối với khả năng khám phá, đáng để dừng lại và suy nghĩ về các bối cảnh khác nhau và chọn một bối cảnh phù hợp nhất.
Cornel Masson

Câu trả lời:


345

reverse()| Tài liệu Django


Hãy giả sử rằng trong bạn urls.pybạn đã xác định điều này:

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

Trong một mẫu, sau đó bạn có thể tham khảo url này như:

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

Điều này sẽ được hiển thị dưới dạng:

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

Bây giờ hãy nói rằng bạn muốn làm một cái gì đó tương tự trong views.pyví dụ của bạn - ví dụ: bạn đang xử lý một số url khác (không phải /foo/) trong một chế độ xem khác (không some_view) và bạn muốn chuyển hướng người dùng đến /foo/(thường là trường hợp gửi biểu mẫu thành công).

Bạn chỉ có thể làm:

return HttpResponseRedirect('/foo/')

Nhưng nếu bạn muốn thay đổi url trong tương lai thì sao? Bạn sẽ phải cập nhật urls.py tất cả các tham chiếu đến nó trong mã của bạn. Điều này vi phạm DRY (Đừng lặp lại chính mình) , toàn bộ ý tưởng chỉ chỉnh sửa một nơi, đó là điều cần phấn đấu.

Thay vào đó, bạn có thể nói:

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

Điều này xem qua tất cả các url được xác định trong dự án của bạn cho url được xác định bằng tên url_namevà trả về url thực tế /foo/.

Điều này có nghĩa là bạn chỉ tham chiếu url theo namethuộc tính của nó - nếu bạn muốn tự thay đổi url hoặc chế độ xem mà nó đề cập đến bạn có thể thực hiện điều này bằng cách chỉ chỉnh sửa một địa điểm - urls.py.


2
FYI, {{ url 'url_name' }}nên {% url url_name %}ở Django 1.4 hoặc sớm hơn. Điều này sẽ được thay đổi trong phiên bản Django tiếp theo (1.5) và sau đó sẽ được {% url 'url_name' %}. Các tài liệu cho templatetag url cung cấp một số thông tin tốt nếu bạn cuộn xuống một chút đến phần "tương thích chuyển tiếp"
j_syk

1
j_syk cảm ơn - tôi đã thực hiện @load url từ tương lai @ kể từ ngày 1.3 xuất hiện và quên rằng nó chưa phải là mặc định. Tôi sẽ cập nhật câu trả lời của mình để nó không gặp sự cố thiếu kinh nghiệm.
scytale

2
đã sửa lỗi - Tôi nghĩ rằng bạn hoàn toàn có thể chấp nhận việc bạn chỉnh sửa lỗi chính tả trong câu trả lời của người khác vì vậy nếu bạn thấy nhiều hơn, hãy nhảy vào :-)
scytale

3
Một trong những câu trả lời tinh tế nhất người ta có thể tìm thấy trên trang web này.
Manas Chaturvedi

1
">>> nhưng điều gì sẽ xảy ra nếu bạn muốn thay đổi url trong tương lai", Những loại tinh tế này hữu ích với 0,0001% thời gian và giải pháp được vận chuyển như một tính năng hữu ích và mọi người sử dụng nó như thể chúng là ' thực hành tốt nhất 'và để lại mớ hỗn độn. TBH nếu khi thay đổi các url trong tương lai, bạn chỉ cần thực hiện thay thế toàn cầu. Ngay cả giải pháp này (sử dụng url_name) cũng dễ gặp phải vấn đề 'nếu bạn muốn thay đổi url_name trong tương lai thì sao?' Được mã hóa trong Django trong hơn 5 năm và chưa đáp ứng nhu cầu url_reverse. Cách tốt nhất để đối phó với những điều kỳ quặc này là từ chối sử dụng chúng.
nehem

10

Đây là một câu hỏi cũ, nhưng đây là một cái gì đó có thể giúp đỡ một ai đó.

Từ các tài liệu chính thức:

Django cung cấp các công cụ để thực hiện đảo ngược URL khớp với các lớp khác nhau nơi cần URL: Trong các mẫu: Sử dụng thẻ mẫu url. Trong mã Python: Sử dụng hàm Reverse (). Trong mã cấp cao hơn liên quan đến việc xử lý URL của các phiên bản mô hình Django: Phương thức get_absolute_url ().

Ví dụ. trong các mẫu (thẻ url)

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

Ví dụ. trong mã python (sử dụng reversechức năng)

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

1
cần ông chủ mô tả đầy đủ
giveJob

OP đặc biệt đề cập rằng anh ấy đã đọc các tài liệu, anh ấy cần giải thích, không chỉ sao chép / dán từ các tài liệu.
RusI

8

Các câu trả lời hiện tại đã làm rất tốt trong việc giải thích những gì của reverse()chức năng này trong Django.

Tuy nhiên, tôi đã hy vọng rằng câu trả lời của tôi rơi nhẹ khác nhau tại sao : tại sao sử dụng reverse()ở vị trí của, cách tiếp cận cho là pythonic hơn đơn giản hơn khác trong mẫu-view ràng buộc, và một số lý do chính đáng cho sự phổ biến của việc này "chuyển hướng là gì qua reverse() mẫu "trong logic định tuyến Django.

Một lợi ích chính là việc xây dựng ngược lại một url, như những người khác đã đề cập. Giống như cách bạn sẽ sử dụng {% url "profile" profile.id %}để tạo url từ tệp cấu hình url của ứng dụng: vd path('<int:profile.id>/profile', views.profile, name="profile").

Nhưng như OP đã lưu ý, việc sử dụng reverse()cũng thường được kết hợp với việc sử dụng HttpResponseRedirect. Nhưng tại sao?

Tôi không chắc chắn đây là cái gì nhưng nó được sử dụng cùng với HttpResponseRedirect. Làm thế nào và khi nào thì đảo ngược () này được sử dụng?

Hãy xem xét những điều sau đây 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)
        ))

Và tối thiểu của chúng tôi 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')
]

Trong vote()hàm, mã trong elsekhối của chúng tôi sử dụng reversecùng với HttpResponseRedirectmẫu sau:

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

Điều này trước hết, có nghĩa là chúng ta không phải mã hóa URL (phù hợp với nguyên tắc DRY) nhưng quan trọng hơn, reverse()cung cấp một cách thanh lịch để xây dựng chuỗi URL bằng cách xử lý các giá trị được giải nén khỏi các đối số ( args=(question.id)được xử lý bởi URLConfig). Giả sử questioncó một thuộc tính idchứa giá trị 5, URL được xây dựng từ reverse()đó sẽ là:

'/polls/5/results/'

Trong mã ràng buộc chế độ xem mẫu thông thường, chúng tôi sử dụng HttpResponse()hoặc render()vì chúng thường liên quan đến ít trừu tượng hơn: một chức năng xem trả về một mẫu:

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

Nhưng trong nhiều trường hợp chuyển hướng hợp pháp, chúng tôi thường quan tâm đến việc xây dựng URL từ danh sách các tham số. Chúng bao gồm các trường hợp như:

  • Gửi biểu mẫu HTML thông qua POSTyêu cầu
  • Đăng nhập người dùng sau khi xác thực
  • Đặt lại mật khẩu thông qua mã thông báo web JSON

Hầu hết trong số này liên quan đến một số hình thức chuyển hướng và một URL được xây dựng thông qua một tập hợp các tham số. Hy vọng điều này thêm vào chủ đề đã có ích của câu trả lời!


4

Chức năng hỗ trợ nguyên tắc khô - đảm bảo rằng bạn không sử dụng url mã cứng trong ứng dụng của mình. Một url nên được xác định ở một nơi và chỉ một nơi - url url của bạn. Sau đó, bạn thực sự chỉ cần tham khảo thông tin đó.

Sử dụng reverse()để cung cấp cho bạn url của một trang, được cung cấp đường dẫn đến chế độ xem hoặc tham số page_name từ url url của bạn. Bạn sẽ sử dụng nó trong trường hợp không có ý nghĩa để làm điều đó trong mẫu với {% url 'my-page' %}.

Có rất nhiều nơi bạn có thể sử dụng chức năng này. Một nơi tôi đã tìm thấy tôi sử dụng nó là khi chuyển hướng người dùng trong chế độ xem (thường là sau khi xử lý thành công biểu mẫu) -

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

Bạn cũng có thể sử dụng nó khi viết thẻ mẫu.

Một lần khác tôi sử dụng reverse()là với thừa kế mô hình. Tôi đã có một ListView trên một mô hình cha mẹ, nhưng muốn lấy từ bất kỳ một trong các đối tượng cha mẹ đó đến Chi tiết đối tượng con của nó. Tôi đã đính kèm một get__child_url()hàm cho cha mẹ đã xác định sự tồn tại của một đứa trẻ và trả về url của Chi tiết đó bằng cách sử dụng reverse().



2

Các câu trả lời hiện có khá rõ ràng. Chỉ trong trường hợp bạn không biết tại sao nó được gọi reverse: Nó lấy đầu vào của một tên url và cung cấp url thực tế, ngược lại với việc có một url trước và sau đó đặt tên cho nó.


1
Chỉ cần học Django từ một hướng dẫn (Django Girls). Đó là một đường cong học tập dốc. Tôi nghĩ rằng tên của chức năng này là khủng khiếp: "dự trữ" mà không có bất kỳ trình độ nào RẤT MONG ĐỢI đề nghị đặt một danh sách hoặc chuỗi, điều này rõ ràng không có gì để làm với nó.
mike gặm nhấm

@mikerodent Mình hoàn toàn đồng ý với bạn. Bên cạnh đó, không có câu trả lời nào giải thích tại sao hàm được gọi là đảo ngược. Đó là một tên xấu imo.
Soham Dongargaonkar

1

Reverse () được sử dụng để tuân thủ nguyên tắc django DRY tức là nếu bạn thay đổi url trong tương lai thì bạn có thể tham chiếu url đó bằng cách sử dụng đảo ngược (urlname).

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.